C语言基础:结构体对齐规则与0字节数组

C语言基础:结构体对齐规则与0字节数组


  • 不同的编译器和系统默认的对齐规则会有差异,这里我使用的win32的MinGW
  • C语言结构体一般是默认四字节对其的。

结构体对其规则

一般的,C语言结构体默认是以4字节对其方式,以此默认4字节为依据,结构体对其规则有以下三项:

  • 规则一:struct内的第一个成员在偏移地址0处,随后成员的偏移地址在其本身类型大小整数倍处
  • 规则二:struct的总大小为内部最大成员类型的整数倍
  • 规则三:当A结构内含有结构B时,B在A中的偏移地址为B结构内最大元素类型的大小的整数倍

示例1:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define debug_printf(value) printf(#value " ---==> %d\n", value)

#define struct_member_offset(struct, member) (((char *)(&(((struct *)0)->member))) - ((char *)0))

typedef struct
{
	uint8_t  a;    // 偏移地址0
	uint32_t b;    // 偏移地址4
	uint8_t  c;    // 偏移地址8
	uint8_t  d;    // 偏移地址9
}test_t;

int main()
{
	int a = struct_member_offset(test_t, a);
	int b = struct_member_offset(test_t, b);
	int c = struct_member_offset(test_t, c);
	int d = struct_member_offset(test_t, d);
	debug_printf(sizeof(test_t));
	debug_printf(a);
	debug_printf(b);
	debug_printf(c);
	debug_printf(d);
	return 0;
}

输出结果:

解析:

  • a为第一个成员在偏移地址0处
  • b成员类型为无符号整形占用四字节,根据规则一b要对齐到4字节地址处,所以偏移地址为4,相当于在a成员后面补齐了3字节,不过这补齐的3个字节没用到
  • c和d成员大小都为1字节,根据规则一要对齐到1字节,所以c偏移为9,d偏移为10
  • 四个成员目前所占用的空间加起来是10字节,但是!此时还没完!根据规则二结构体的总大小为结构内最大成员的整数倍,test_t这个结构内最大成员是b占用4字节,所以10字节还要补齐2字节去对齐4字节,所以sizeof(test_t)=12。

示例二:

现在将d成员改为uint64类型:

typedef struct
{
	uint8_t  a;
	uint32_t b;
	uint8_t  c;
	uint64_t  d;
}test_t;

输出结果:

还是根据规则解析:

  • a在偏移地址0处
  • b在4处
  • c在8处
  • abc所占用的空间为9个字节,d为uint64类型占8个字节,所以要对齐到8字节处,也就是偏移地址16处,相当于c成员后补齐了7字节。
  • 目前四个成员所占用的空间为24字节,24是d类型的倍数大小,所以sizeof(test_t)=24

示例三:
现在将结构改为如下,多了一个数据

typedef struct
{
	uint8_t  a;
	uint32_t b;
	uint8_t c[3];
	uint8_t  d;
	uint64_t  e;
}test_t;

输出结果:

c成员为3字节,占用偏移地址8,9,10三个空间,所以总大小还是24。


示例四:
将结构改为如下,现在test_t结构内包含结构sub_t。

typedef struct
{
	uint8_t sub_a;
	uint32_t sub_b;
}sub_t;

typedef struct
{
	uint8_t  a;
	uint32_t b;
	sub_t c;
	uint8_t  d;
	uint64_t  e;
}test_t;

输出结果:

解析:

  • 根据规则一和二解析sizeof(sub_t)=8字节
  • 根据规则三确定sub_t在test_t中的偏移地址肯定是4的整数倍处,所以c这个结构成员偏移地址为8
  • d偏移地址为17
  • e偏移地址为24
  • sizeof(test_t)=32

字节为0的数组与结构体

先看一下0字节数组的大小:

int main()
{
	int array[0];
	debug_printf(sizeof(array));
	return 0;
}

输出结果:

sizeof(array) ---==> 0

说明0字节数据占用空间为0,那么看下面这个例子:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define debug_printf(value) printf(#value " ---==> %d\n", value)

#define struct_member_offset(struct, member) (((char *)(&(((struct *)0)->member))) - ((char *)0))

typedef struct
{
	uint8_t  a;
	uint32_t b;
	uint8_t  c;
	uint64_t  d[0];
}test_t;

int main()
{
	int a = struct_member_offset(test_t, a);
	int b = struct_member_offset(test_t, b);
	int c = struct_member_offset(test_t, c);
	int d = struct_member_offset(test_t, d);
	debug_printf(sizeof(test_t));
	debug_printf(a);
	debug_printf(b);
	debug_printf(c);
	debug_printf(d);
	return 0;
}

输出结果:

!!奇怪的问题出现了!!

但道理说d成员占用空间为0,sizeof(test_t)应该是12才对,但是sizeof(test_t)却是16!!

原因:d成员虽然占用空间为0,但是他是uint64类型的,结构体的总大小是按照内部最大成员进行对齐的!test_t对齐到了8字节,所以sizeof(test_t)的大小为16字节!


ends…

微信扫码订阅
UP更新不错过~
关注
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

觉皇嵌入式

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值