小明在某个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语言程序员的工作其实就是堆积木,再复杂的项目也是一点一点堆积起来的。如果我们对每一个基础积木都了如指掌,那么制作任何形状的积木应该都不在话下。