首页 > 编程知识 正文

精通C语言C99伸缩型数组成员Flexible array member

时间:2023-05-04 16:11:42 阅读:190284 作者:3326

我就职于国际知名终端制造商,负责调制解调器芯片的开发。

5G初期负责终端数据业务层、核心网相关开发,目前带动6G计算网络技术标准研究。

博客的内容主要包括

5G协议说明

计算能力网络课程(云计算、边缘计算、终端计算() )。

高级c语言授课

Rust语言说明

文章目录C99伸缩型数据成员一、声明一个伸缩型数组成员二、伸缩型数组成员的限制三、伸缩型数组成员与指针的区别四、ISO C99伸缩型数组成员与GCC中零长数组的区别GCC中的扩展

C99伸缩型数据成员

C99添加了一个使用名为扩展数组成员(Flexible array member )的新特性声明的结构,其中每个数组成员具有以下特性:

此数组不会立即存在(不占用内存)。 使用此伸缩数组成员,可以编写适当的代码,使其实际存在,并具有所需数量的元素。 一.声明伸缩性数组成员首先看伸缩性数组成员的示例:

struct flex{int count; double average; double scores[]; //伸缩型数据成员; 声明伸缩数组的成员有以下规则:

伸缩型数组的成员为最后; 结构中声明结构的最后一个成员伸缩数组与常规数组类似,但如果声明类型为必须至少有一个成员struct flex的结构变量,则scores无法执行任何操作。 因为此数组没有保留存储空间,所以请参阅它的方括号中是空的以下示例:

# include stdio.h # include stdlib.h # define courses _ num3# pragma pack (4) struct flex{ int count; double average; double scores[]; //伸缩型数组成员; int main ()//编译器没有为scores数组分配内存printf(structflexsize%ZD(n ),sizeof )。 //struct flex * person=malloc (sizeof ) struct flex (courses _ num * sizeof ) double )分配给结构和数组; person-count=COURSES_NUM; 人员- scores [0]=95 . 人员- scores [1]=100 . 人员- scores [2]=80 . 人员-平均值=(人员- scores [0]人员- scores [1]人员- scores [2] )/3 . printf (个人资料% lf (n ),个人资料); 个人; 返回0; }输出如下图所示。

sizeof(structflex )==12表示编译器没有为scores数组保留内存空间。

二、对伸缩型数组成员的限制首先,不能用结构进行赋值和复制。 例如,下面的代码是错误的。

struct flex *人员1,*人员2; //*人员1、*人员2均为结构*人员1=*人员2;我们需要通过malloc等类似函数给scores数组分配内存如果判断错误要复制,请使用memcpy ) )之类的函数进行操作。

第二,不要按值将此结构传递给函数。 原因相同,按值传递参数与赋值类似。只能拷贝除伸缩型数组成员之外的其它成员

第三,要把结构的地址传递给函数

三.伸缩性数组成员与指针的区别一:编译器为结构不要使用带伸缩型数组成员的结构作为数组成员或另一个结构的成员,见:

# include stdio.h # include stdlib.h # define courses _ num3# pragma pack (4) struct flex{ int count; double average; double scores[]; //伸缩型数组成员; struct pointer{ int count; double average; 双精度* scores; //指针

数据成员};int main(){ //编译器并没有给 scores 数组分配内存 printf("struct flex size %zdn",sizeof(struct flex)); //编译器给 scores 指针分配内存 printf("struct pointer size %zdn",sizeof(struct pointer)); return 0;}

结果输出如下:

博主使用的是64位操作系统,所以指针占用了8B存储空间,然而伸缩型数组在声明时并未占用存储空间。

       区别二:成员地址分配不同,看下图解释:

上图应该解释的很清楚了,伸缩型数组成员中存储的数据与其在结构中紧邻的上一个成员存储的数据在内存的逻辑地址上是连续的。而指针数据成员中存储的存放数据的逻辑地址,不一定与其结构中紧邻的上一个成员存储的数据在内存逻辑地址上连续。

这也是为什么不建议使用带伸缩型数组成员的结构作为数组成员或另一个结构的成员。

看下面的Demo code:

#include<stdio.h>#include<stdlib.h>#define COURSES_NUM 3#pragma pack(4)struct flex{ int count; double average; double scores[]; //伸缩型数据成员};struct pointer{ int count; double average; double *scores; //数据成员};int main(){ struct flex * person_flex = malloc(sizeof(struct flex)+COURSES_NUM*sizeof(double)); struct pointer * person_pointer = malloc(sizeof(struct pointer)); person_pointer->scores = malloc(COURSES_NUM*sizeof(double)); printf("[person_flex] average address is %p , scores address is %pn", &person_flex->average,person_flex->scores); printf("[person_pointer] average address is %p , scores address is %pn", &person_pointer->average,person_pointer->scores); free(person_flex); free(person_pointer->scores); free(person_pointer); return 0;}

输出结果如下:

这里的对比并不是说谁好谁坏,好与坏取决于项目中的具体应用!


四、ISO C99伸缩型数组成员 与 GCC中的零长度数组的区别

       其实本质还是相同的,只不过在GCC中的声明语法如下:

struct line { int length; char contents[0]; // Zero-length array};struct line *thisline = (struct line *)malloc (sizeof (struct line) + this_length);thisline->length = this_length; GCC中的扩展

       GCC中允许对伸缩型数组成员静态初始化,这个过程等价于定义了一个新的结构体,包含原始的数据成员以及足够容纳初始数组对象的数组,看下面的code:

struct f1 { int x; int y[];} f1 = { 1, { 2, 3, 4 } };//等价于定义一个新结构体struct f1 { int x; int y[3];};

       GCC中允许有伸缩型数组对象的结构,内嵌在其它结构或联合中,对于这类结构的初始化有一些限制:

只允许对顶层的结构进行非空初始化(Non-empty initialization)如果是非顶层成员,只能进行空初始化

看下面的code:

struct f1 { int x; int y[3];};struct f2 { struct f1 f1; int data[3];}; /* 有效,非顶层空初始化 { 2, 3, 4 }初始化数组data 而data的逻辑地址与f1结构中的y相同,等价于静态初始化了f1结构中的伸缩型数组y*/struct f2 _f2 = { { 1 }, { 2, 3, 4 } }struct foo { int x; int y[]; };struct bar { struct foo z; };struct foo a = { 1, { 2, 3, 4 } }; //顶层所以有效struct bar b = { { 1, { 2, 3, 4 } } }; //非顶层所以无效struct bar c = { { 1, { } } }; //非顶层空初始化,有效struct foo d[1] = { { 1, { 2, 3, 4 } } }; //非顶层非空初始化,无效

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。