8

怎样获得C语言结构体成员的长度呢?

 4 years ago
source link: https://blog.popkx.com/%E6%80%8E%E6%A0%B7%E8%8E%B7%E5%BE%97c%E8%AF%AD%E8%A8%80%E7%BB%93%E6%9E%84%E4%BD%93%E6%88%90%E5%91%98%E7%9A%84%E9%95%BF%E5%BA%A6%E5%91%A2/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

小明在某个C语言项目开发中定义了一个结构体 parent,该结构体包含一个数组成员 char text[255],相关C语言代码如下,请看:

typedef struct _parent
{
  float calc ;
  char text[255] ;
  int used ;
} parent_t ;

小明的问题

随后,他发现项目需要定义结构体 child,并且 child 中也需要一个数组成员,不过该数组成员要与 parent 中的 text 成员一样长,有什么办法吗?小明尝试了下面这样的定义方法:

typedef struct _child
{
  char flag ;
  char text[sizeof(parent_t.text)] ;
  int used ;
} child_t ;

但是C语言编译器显然不会接受 parent_t.text 这种“类型名.成员名”的写法,所以小明只能按照下面这种方式定义:

parent_t* dummy ;
typedef struct _child
{
  char flag ;
  char text[sizeof(dummy->text)] ;
  int used ;
} child_t ;

之所以将 dummy 定义为指针,是因为指针的宽度是固定的,无论它索引多长的内存。如果将其定义为普通变量:parent_t dummy; 那么 dummy 显然会占用更多内存空间。

但是这种方法并不好,为了获得 parent_t 结构体中的 text 成员大小,专门定义了 dummy 指针,这显然不够优雅,并且还可能会对C语言程序项目的命名空间产生干扰。那么有什么别的办法吗?

自然是有的,事实上,要实现小明的目的,方法不止一种,下面将介绍几种在C语言程序开发中常用的用于确定结构体成员长度的方法。

使用 define 宏定义

相信读者应该注意到了,小明在定义 parent 结构体的成员 text 长度时,使用的是常数“255”。这种被直接使用数字定义数组的方式,其实是不推荐的,它会为整个C语言项目带来很多不方便,一个最明显的例子就是小明遇到的问题。

另外,直接使用数字定义数组也不利于后期维护。因为一旦后期发现需要修改 text 成员的长度,C语言程序员将不得不回到代码中,修改所有相关的数字。如果有别的代码也使用了 255 这个数字,程序员还得特别小心甄别该处C语言代码是否也需要修改。

因此,在定义数组时,更推荐的做法是使用 define 宏定义。C语言中的 define 宏定义虽然只是简单的替换,但是它可以给被替换者(例如数字)取名,既能为代码带来可读性,又能方便后期维护,同时也能为C语言项目开发本身带来便利。

#define        TEXT_LEN    255

typedef struct _parent
{
  float calc ;
  char text[TEXT_LEN] ;
  int used ;
} parent_t ;

typedef struct _child
{
  char flag ;
  char text[TEXT_LEN] ;
  int used ;
} child_t ;

上述C语言代码使用 define 宏定义定义了 text 成员的长度,可见,这种方式不仅解决了小明的问题,而且在后续的开发中,程序员看到 TEXT_LEN 定义本身,也能明白该宏代表的意义(text长度)。以后要是需要修改 text 的长度,只需修改 TEXT_LEN 宏定义本身就可以了。

使用 define 宏定义并不是正面解决小明的问题,只不过给出了另外一种比较推荐的解决方案而已,有点像耍“小聪明”。有些读者并不喜欢这种方式,那有没有别的解决方法呢?

自然是有的。不知道读者是否还记得,在我之前的一篇文章里,讨论获得结构体成员的偏移量时,曾经定义过类似于下面这样的宏:

#define OFFSET(type, member)      \
    ( (size_t)( &( ((type*)0)->member)  ) )

读者应将注意力放在((type*)0)->member,显然,如果要获取C语言结构体某个成员的长度,可以再结合 sizeof() 关键字,定义下面这样的方法:

#define member_size(type, member) \
    sizeof(((type *)0)->member)

原理是简单的,上述C语言代码中的数字“0”可看作是一个地址,它被强制转换为 type * 指针型,因此可以索引结构体 type 的成员 member。使用 member_size() 方法获得 parent 结构体中的 text 成员长度是简单的,请看下面的C语言代码:

typedef struct _child
{
  char flag ;
  char text[member_size(parent_t, text)] ;
  int used ;
} child_t ;

巧用 typedef

如果读者觉得利用指针繁琐,还有一种方法可以在 child 结构体中定义和 parent 结构体中 text 成员一样长的成员。这个方法是简单的,请看下面的C语言代码:

typedef char description[255];

// 在 parent 和 child 中
description text;

上面这段C语言代码利用 typedef 关键字定义了一个特殊的数据类型 description,该类型为长度等于 255 字节的 char 型数组。此时,只要在 parent 和 child 结构体中定义 text 成员都使用该类型,就能保证 child.text 和 parent.text 一样长了。

应该明白,本节给出的解决小明问题的方法只是抛砖引玉,而且容易看出,这些方法其实都是基础知识的堆积。我在之前的文章中曾说,C语言程序员的工作其实就是堆积木,再复杂的项目也是一点一点堆积起来的。如果我们对每一个基础积木都了如指掌,那么制作任何形状的积木应该都不在话下。


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK