结构体及柔性数组

转载前注明出处,欢迎转载分享

结构体:
大小:结构体的大小不是说结构体中的每个变量的数据类型之和就是结构体的大小,而是 按照内存对齐的方式来计算的。
1
2
3
4
5
6
7
8
9
struct test
{
    
char a;
    
int b;
    
char c;
    
char *d;
    
short e;
    
long long f;
};     
//64位上此结构体大小为40  并非1+4+1+8+4+8=26
不懂的小伙伴戳这里:(1)内存对齐的详细解释/(2) 内存对齐的详细解释

默认编译的时候结构体设定为4字节对齐,当然我们可以修改其对齐方法,代码如下:
1
#pragma pack(2//以二字节方式对齐

那么一个空结构体占多大内存你知道么?
看如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct {};

int main()
{
    
struct d1;
    
struct d2;

    printf(
"%d\n"sizeof(struct D));
    printf(
"%d, %0x\n"sizeof(d1), &d1);
    printf(
"%d, %0x\n"sizeof(d2), &d2);

    
return 0;
}
gcc编译结果:
0
0, dd76fcd0
0, dd76fcd0

g++编译结果:
1
1, e906651f
1, e906651e

说到空结构体就得说说C语言的“灰色地带”, C语言中空结构体占用的大小是0(在gcc中测试为0)。在C++中规定空结构体和空类所占内存大小为1。
C++语言标准规定“no object shall have the same address in memory as any other variable”,C++这样的规定原因如下:
1
2
3
struct {};
arr[
5]; //定义对象数组
int cnt &arr[4&arr[0]

这种指针相减运算在编译器中会等价于如下步骤:
1
2
3
struct {};
arr[
5]; //定义对象数组
cnt ((char *)&arr[4(char *)&arr[0]) sizeof(D);

如果允许C++对象大小为0,那么这里的运算将产生两个问题: (1) 不能通过指针区分不同的数组对象; (2) sizeof D为0导致非法的除0操作。这样一来,编译器还需要用一些复杂的代码来处理这些异常情况信息。为了满足C++标准规定的不同对象不能有相同地址,C++编译器保证任何类型对象大小不能为0。 C++编译器会在空类或空结构体中增加一个虚设的字节,以确保不同的对象都具有不同的地址。


柔性数组:
结构体中最后一个元素允许是未知大小的数组,这个数组就是 柔性数组(soft array),也叫 伸缩性数组。但结构中的柔性数组前面必须 至少一个其他成员,如果是下面的情况则gcc编译错误:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct
{
    
int arr[];
};
//error

int main()
{
    
struct d1;
    
struct d2;

    printf(
"%d\n"sizeof(struct D));
    printf(
"%d, %0x\n"sizeof(d1), &d1);
    printf(
"%d, %0x\n"sizeof(d2), &d2);

    
return 0;
}

但是g++编译可以通过,运行结果如下:
0
0, 1442db70
0, 1442db70 

这和gcc编译空结构体的运行结果相似,接下来写一段简单的柔性数组的创建和运用,代码如下:
  C Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include stdio.h >
#include stdlib.h >
#include string.h >

#define NUM 10 //the length of softarray

typedef struct softarray
{
    
int len;
    
int array[];
SoftArray; 
//init softarray


//create softarray
SoftArray *create_softarray()
{
    SoftArray *tmp (SoftArray *)malloc(
sizeof(SoftArray) sizeof(*(tmp->array)) NUM);
    memset(tmp, 
0sizeof(*(tmp->array))); //be zero
    tmp->len NUM;
    
return tmp;
}

void print_softarray(SoftArray *tmp)
{
    
int 0;
    
for(i 0NUM; i++)
    {
        printf(
"%d\n"*(tmp->array) i);
    }
}

void delete_softarray(SoftArray *tmp)
{
    free(tmp);
}

int main()
{
    SoftArray *SA create_softarray();
    print_softarray(SA);
    delete_softarray(SA);
    
return 0;
}

总结:也就是说对于空结构体而言,在gcc环境下编译结果显示该结构体所占空间大小为0,并且不同对象的地址相同。在g++环境下编译结果显示该结构体所占空间大小为1,并且不同对象的地址不同。如果结构体中仅为一个没有指定大小的数组时,用gcc编译会报错,而用g++编译时显示的结果是该结构体所占空间大小为0,并且不同对象的地址相同。


struct与union的区别:
struct中的每个域在内存中都独立分配空间
union只分配最大域的空间,所有域共享这块空间

代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct A{
    
int a;
    
int b;
    
int c;
};

union B{
    
int a;
    
int b;
    
int c;
};

int main(){
    printf(
"%d\n"sizeof(struct A)); //12
    printf("%d\n"sizeof(union B));  //4

    
return 0;
}
输出分别为12和4
看到上述代码我们可以猜测出union的大小取决于其中一个类型的最大域。
来看如下代码:
  C Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include < stdio.h >
union A
{
    
int f1;
    
float f2;
    
int f3;
    
char a[9];
};

int main()
{
    
union a1;
    a1.f3 
5;

    printf(
"%d\n"sizeof(a1));
    
//printf("%d\n", a1.f1);

    
return 0;
}
按照上述猜测,这段代码的输出结果应该是9呀,怎么会是12呢?这跟 union的 内存对齐有关系。首先 找出联合的最大类型为int,然后 找出联合成员中占空间最大的是a[9],即占用9个字节,所以该联合大小至少为9,因为要满足与最大类型(这里是int)对齐的条件,所以要 整除最大类型即int(4字节),给9补齐3个字节,所以最终联合的大小为12个字节。


  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值