C语言结构体打包的意义

本文探讨了C语言中结构体打包和内存对齐的重要性,讲解了对齐要求、填充(padding)原则,并通过实例展示了结构体成员重排如何减少内存浪费。在现代处理器上,对齐规则有助于提升数据存取速度,但过度使用pragma pack可能导致代码效率降低。文章还提到了结构体中位域、怪异数据类型以及可读性和缓存局部性等因素在结构体设计中的考虑。
摘要由CSDN通过智能技术生成
 计算机课程指引人们避开微观的优化而去寻找更优的算法。 硬件价格的下降也使挤压内存占用变得没 有必要。 但该技术仍在重要的情况下有用武之地,而且只要内存有限制,就会有用。 这篇文章的目的是使C程 序员重新发现该技术,使他们能专注于更重要的事情。

1. 对齐的要求

    首先要理解的是,在现代处理器上,C编译器在内存里存放基本数据类型时是受限的:以最快存取速度 为目标。 在X86或ARM上,基本数据类型并不是存放在任意内存地址上的。 每种类型除了char都有对齐要求 (alignment requirement); char类型可以开始于任何地址,但2字节的short类型必须存放在偶数地址 上,4字节的整型或浮点型必须放在能被4整除的位置上,而8字节的long或double型必须放在能被8 整除的地址上。有符号或无符号没有差别。

    用术语来讲就是,基本C类型在X86和ARM上都是自对齐的(self-aligned)。指针,不管是32位(4字 节)还是64位(8字节)也是自对齐的。 自对齐能存取得更快是因为它能用一条指令来存取该类型数据。 另一方面,如果没有对齐限制,代码 可能会在跨机器字边界存取的时候使用两条以上的指令。 字符是特殊情况: 不管它在们在机器字的哪 个位置,存取代价都是一样的。所以它们没有对齐要求。


    在现代处理器上,是因为在有些更老的处理器上,强迫你的C代码违反对齐限制(比如,把一个奇数地 址转换为int指针并试图使用它)不仅会让你的代码变慢,还会造成非法指令异常。 比如在Sun SPARC 芯片上就是这样。 事实上,只要有足够的决心和正确的硬件标志(e18),你也可以在X86上触发该异常

    自对齐还不是唯一的规则。 历史上,有些处理器(特别是那些没有barrel shifters的)有更严格的规 则。如果你在做嵌入式系统,你可能撞到这些暗礁。要有心理准备。

    有时你可以让编译器不遵守处理器的正常对齐规则,一般是使用pragma,比如 #pragma pack。 请不 要随意使用,因为它会生成开销更大、更慢的代码。 通过使用我介绍的技术,你可以节省同样、甚至 更多的内存。 使用#pragma pack的唯一合理理由是,你需要C数据分布完全匹配某些硬件或协议,比如一个经过内存 映射的物理端口,则不违反对齐规则就无法做下去。 如果你处在那种情况,而不理解本文的内容,你 会遇到大麻烦。
 
2. 填充(padding)
 
    现在我们来看一个简单的例子,变量在内存中的分布。 
    char *p;  
    char c;  
    int x;  
    如果你不知道数据对齐,你可能会假定这三个变量在内存里占用连续的字节。 即,在32位机器上4字节 的指针后面会紧跟1字节的char,而它后面会紧跟4字节的int。在64位机器上,唯一的差别是指针是8字 节的。

    而实际情况是这样的(在x86或ARM或任何自对齐的机器上):p 存储在4字节或8字节对齐的位置上(由机 器的字长决定)。 这是指针对齐-可能的最严格的情况。 c的存储紧跟着p。但x的4字节对齐要求造成一个缺口,就好像有第四个变量插入其中:
    char *p;      /* 4 or 8 bytes */  
    char c;       /* 1 byte */  
    char pad[3];  /* 3 bytes */  
    int x;        /* 4 bytes */  
    pad[3] 数组表示有3个字节浪费了。 老式的说法是“slop(溢出)”。

    比较如果x 是2字节的short会怎样:
    char *p;  
    char c;  
    short x;  
    在这种情况下,实际的内存分布是这样的:
    char *p;      /* 4 or 8 bytes */  
    char c;       /* 1 byte */  
    char pad[1];  /* 1 byte */  
    short x;      /* 2 bytes */  

    另一方面,如果是在64位机上,x 是一个long:
    char *p;  
    char c;  
    long x;  
    我们会得到:
    char *p;     /* 8 bytes
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值