C语言结构体打包的意义

 计算机课程指引人们避开微观的优化而去寻找更优的算法。 硬件价格的下降也使挤压内存占用变得没 有必要。 但该技术仍在重要的情况下有用武之地,而且只要内存有限制,就会有用。 这篇文章的目的是使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
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值