incomplete types(types thatdescribe objects but lack information needed to determine their sizes).[1]
不完整类型是一种用于描述标识符但是缺少决定该标识符大小所需信息的类型。不完整类型可以是结构类型(struct)、联合类型(union)、数组类型(array)和void类型。
不完整类型必须通过某种方式补充完整,否则不能进行实例化,其成员也不能够被访问。
不完整类型的典型用法如迭代结构体(recursive structures)的声明和定义。例如:
typedef struct AType atype; //不完整类型 typedef struct BType btype; //不完整类型 struct AType{ btype *bt; int cnt; }; struct BType{ atype *at; int cnt; };
不完整类型也常被用于数据隐藏。例如,将不完整类型声明在头文件中,而真正的定义则在源文件中。
//头文件中声明 extern int money[];
//源文件中定义 int money[] = {10, 20};
柔性数组成员也称为伸缩型数组成员,其定义如下:
The last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.[2]
即在具备大于一个命名成员的结构中,最后一个元素可以是不完整类型,称为柔性数组成员。柔性数组成员是C99标准中引入的一个新特性,其目的在于满足对动态结构体(即变长度结构体)的需求。
首先,我们来看看固定长度结构体的定义和使用。以通信过程中的消息定义为例,假定每次通信的最大消息长度为1460字节,则可以定义结构体如下:
struct message{ intmsg_len; char msg_data[1460]; };
对于这样的定长结构体,当需要传输的消息达不到1460字节时(比如传递握手消息“hello”,长度为5字节),就会造成消息数据字段的浪费。
struct message hello_msg; hello_msg.msg_len= strlen("hello") + 1 ; strcpy(hello_msg.msg_data, "hello", strlen("hello")); send(socket, (char*)&hello_msg, sizeof(struct message));
如果采用柔性数组成员的方式来实现,则不会造成浪费。以上面的例子再重新实现一次,假定传输的数据依旧为”hello”。
struct message{ int msg_len; char msg_data[]; }; char *pMsgData = "hello"; struct message *pMsg = (struct message *) malloc(sizeof(struct message) + strlen(pMsgData) + 1); pMsg->msg_len = strlen(pMsgData) + 1; strcpy(pMsg->msg_data, pMsgData, strlen(pMsgData)); send(socket, (char *)pMsg, sizeof( struct message)+ strlen(pMsgData) + 1); free(pMsg);
需要注意的几点是,C规范中规定不能定义长度为0的数组,不过,大多数编译器将长度为0的数组成员作为非标准进行扩展,因此也可以定位长度为0的数组作为柔性数组成员,形同 char msg_data[0];柔性数组的成员只能堆上生成。
参考文献
[1]. ISO/IEC 9899:TC3. http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf.Section 6.2.5. Sep 7, 2007.
[2]. ISO/IEC 9899:TC3. http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf.Section 6.7.2.1. Sep 7, 2007.