加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 为什么填充必须是2的幂?

发布时间:2020-12-16 06:49:22 所属栏目:百科 来源:网络整理
导读:我正在做一些示例程序来探索C,并想知道为什么结构填充只能以2的幂来完成. #include stdio.h#pragma pack(push,3)union aaaa{ struct bbb { int a; double b; char c; }xx; float f;};#pragma pack(pop)int main(){printf("n Size: %d",sizeof(union aaaa));
我正在做一些示例程序来探索C,并想知道为什么结构填充只能以2的幂来完成.

#include <stdio.h>

#pragma pack(push,3)

union aaaa
{

   struct bbb
   {
      int a;
      double b;
      char c;
   }xx;

   float f;
};

#pragma pack(pop)

int main()
{

printf("n Size: %d",sizeof(union aaaa));

return 0;
}

在编译时

warning: alignment must be a small power of two,not 3 [-Wpragmas]
warning: #pragma pack (pop) encountered without matching #pragma pack (push) [-Wpragmas]

似乎#pragma没有效果.输出仅为24.即4字节对齐.

解决方法

简短的回答是处理器中的基本对象具有小的2的幂(例如,1,2,4,8和16字节),并且存储器被组织成大小为2的小功率的组(例如,8因此,必须对齐结构才能与这些尺寸一起使用.

长期的答案是,其原因是基于物理学和初等数学.计算机自然使用位,值为0和1.这是因为很容易设计在两个值之间切换的物理事物:高电压和低电压,存在充电或没有电荷等等.区分三个值更难,因为您必须对值之间的转换更敏感.因此,随着计算机技术在几十年的发展,我们使用了比特(二进制数字)而不是像三位数这样的替代品.

为了得到更大的数字,我们组合了多个位.因此,两个位可以组合成四个值.三位可以有八个值,依此类推.在较旧的计算机中,有时一次是第六组或第十组.然而,八个变得普遍,现在基本上是标准的.对一个字节使用八位并不像我描述的其他一些分组那样具有强大的物理原因,但它是世界的方式.

计算机的另一个特性是内存.一旦我们拥有这些字节,我们就希望将它们存储在一个易于处理器访问的设备中,这样我们就可以快速地将大量字节输入和输出处理器.当我们有很多字节时,我们需要一种方法让处理器告诉内存处理器想要读或写的字节.因此处理器需要一种方法来处理字节.

处理器使用位作为值,因此它将使用位作为地址值.因此,内存将被构建为接受位以指示当处理器读取时要向处理器提供哪些字节或者当处理器写入时要存储哪些字节.存储器设备对这些位做了什么?一个简单的方法是使用一位来控制通向存储器的路径的一个开关.内存将由许多存储字节的小部分组成.

考虑一下存储设备中可以存储一个字节的东西,并考虑其中两个相邻的东西,比如A和B.我们可以使用一个开关来选择我们是想要A字节是活动还是B字节到积极点.现在考虑其中的四个,比如A,B,C和D.我们可以使用一个开关来选择是使用A-B组还是使用C-D组.然后另一个开关选择A或B(如果使用A-B组)或C或D(如果使用C-D)组.

此过程继续:内存地址中的每个位选择要使用的一组存储单元. 1位选择2个存储单元,2个选择4个,3个选择8个,4个选择16个,依此类推. 8位选择256个存储单元,24位选择16,777,216个存储单元,32位选择4,294,967,296个存储单元.

还有一个并发症.在处理器和内存之间移动单个字节很慢.相反,现代计算机将内存组织成更大的部分,例如八个字节.您只能在内存和处理器之间一次移动八个字节.当处理器请求存储器提供一些数据时,处理器仅发送地址的高位 – 低三位选择八个字节内的单个字节,并且它们不被发送到存储器.

这是更快的,因为处理器在内存完成所有切换以提供一个字节所需的时间内获得8个字节,并且它更便宜,因为您不需要大量额外的开关来区分个体内存中的字节数.

但是,现在它意味着处理器无法从内存中获取单个字节.当您执行访问单个字节的指令时,处理器必须从内存中读取8个字节,然后在处理器内部移动这些字节以获得所需的一个字节.类似地,为了获得两个或四个字节,处理器读取八个字节并仅提取所需的字节.

为简化此过程,处理器设计人员指定数据应以某种方式对齐.通常,它们需要将两字节数据(如16位整数)对齐到两个字节的倍数,四字节数据(如32位整数和32位浮点值)对齐到四的倍数字节和八字节数据对齐到八个字节的倍数.

这种必需的对齐有两个影响.首先,因为四字节数据只能从从存储器(开始或中间)读取的8字节块中的两个位置开始,所以处理器设计者只需要插入电线以从两个位置提取四个字节.如果允许任何对齐,它们不需要添加所有额外的线来从八个单独字节中的任何一个中提取四个字节,这些字节可能是起始位置. (某些处理器将完全禁止加载未对齐的数据,并且一些处理器将允许它但使用慢速方法来提取它使用更少的线但使用迭代算法在几个处理器周期内移位数据,因此未对齐的负载很慢.)

第二个影响是,因为四字节数据只能从八字节块中的两个位置开始,所以它也会在该块内部结束.考虑如果您尝试加载从8字节块的第六个字节开始的四个字节的数据会发生什么.前两个字节在块中,但接下来的两个字节在内存中的下一个块中.处理器必须从内存中读取两个块,从每个块中取出不同的字节,然后将这些字节放在一起.这比读取一个块慢得多.

因此,存储器由2的幂组织,因为这是位的自然结果,并且处理器需要对齐,因为这使得存储器访问更有效.对齐自然是2的幂,这就是为什么当它们是用于对齐的2的幂的倍数时,你的结构尺寸更好.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读