C语言结构体的大小计算和位段

在计算结构体的大小的时候,我们需要考虑内存对齐问题,这也是比较热门的考点之一

结构体内存对齐的规则(本篇文章全部以VS编译器来做示例)

我们在编译器中可以使用#pragma pack(8)来自行设定默认对齐数,#pragma pack()还可以用这段代码来取消自行设定默认对齐数

1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值
VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

1.结构体的大小计算

1.1普通结构体的大小计算

这里我们可以用一段代码来做示例

struct S1
{
 char c1;
 int i;
 char c2;
};

这是C语言中定义的一个结构体,那他的大小怎么来计算呢?

首先我们用一个图来解释

首先我们遵从第一条,让第一个放在偏移量为0的位置

然后c1占用一个字节,所以i要从偏移量为1的位置开始找

然后根据第二条,取最小偏移量,默认的偏移量为8,而int的偏移量为4,所以int应该放到偏移量为4的位置,然后int占用4个字节,依次给他4个空间

最后看c2,取最小偏移量,默认值为8,而char的偏移量为1,所以char应该放到偏移量为8的位置,然后char占用1个字节,依次开1个空间

然后看0-8一共占用了9个字节,在根据第三条规则这个结构体中的最大偏移量是int的4,所以结构体的大小应该为4的倍数,应该是12,所以这个结构体所占用的字节数是12个字节

但是如果我们对代码进行改进,变成这样

struct S2
{
 char c1;
 char c2;
 int i;
};

 根据上面的方法可以得到,结构体的大小变成了8,也就节省了4个字节的空间,所以我们定义结构体的时候,最好把占用空间较小的变量放到前面,这样可以提高内存的利用率

1.2嵌套结构体的大小计算

看一段代码

struct S3
{
 double d;
 char c;
 int i;
};

struct S4
{
char c1;
struct S3 s3;
double d;
};
printf("%d\n", sizeof(struct S4));

这里我们可以看到,S4进行了结构体的嵌套使用,那么这种情况下应该怎么计算呢?

首先我们用前面的方法可以计算出S3的最大对齐数位8,占用的空间16个字节

然后嵌套之后,看上面的第四条规则:

如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
也就是说S4里面嵌套的S3的对齐数应该是8,大小是16个字节,我们依旧用一个图来理解

 这里我们套用上面的几条规则之后,得出的结果应该是32个字节,如果你不相信我就去测试一下

可以看到,我们的结果完全正确

1.3为什么会存在内存对齐

 

大部分的参考资料都是如是说的:
1. 平台原因 ( 移植原因 )
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常。
2. 性能原因
数据结构 ( 尤其是栈 ) 应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
总体来说:
结构体的内存对齐是拿 空间 来换取 时间 的做法。

2.位段

位段的基本要求

1. 位段的成员必须是 int unsigned int signed int 或者char
2. 位段的成员名后边有一个冒号和一个数字。
比如:
struct A {
 int _a:2;
 int _b:5;
 int _c:10;
 int _d:30;
};

位段的基本大小是以比特位单位的

1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以 4 个字节( int )或者 1 个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
这个代码的大小应该是8个字节,因为一次开4个,用完再开4个,所以应该是4的整数倍

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值