`
ihuashao
  • 浏览: 4710788 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

谈谈对齐(中)

阅读更多

谈谈对齐(中)

1.3 变量对齐会带来什么麻烦?

我在变量对齐问题上吃过一次亏,可以作为本节的一个例子。不过要理解这个例子,读者必须知道ARM CPU的一个特点:就是长度为m的基本变量必须放在mn边界上,否则读写时会发生数据访问错误,其中m=2或4。这就是第3节要介绍的数据对齐。

事情是这样,我定义了几个缓冲区(大数组),然后动态分配这些内存。我的错误在于将这些数组定义为字节数组。我的分配算法是按块分配,每个数据块的大小都是4的整数倍。读者能猜到错误产生的原因了吗?

由于我把缓冲区定义为字节数组,编译器就可以把它们放在1n边界。如果缓冲区的起始地址是奇数地址,从缓冲区分配的内存块的起始地址都是奇数地址。如果这些内存块被用于需要按2或4字节对齐的变量,读写时就会发生数据访问错误。如果编译器恰好把这些缓冲区放在4n边界上,问题就不会暴露出来。所以前一次编译可能是好的,但是下一次编译就会发生莫名其妙的错误。调试程序与侦破案件差不多,离犯罪现场越远的凶手就越难发现。在我透过各种表象找到根源之前,吃点苦头是难免的。

解决问题的方法很简单,将缓冲区定义为unsigned int(下文记作uint32)的数组,编译器自然会把它们放到4n边界。在嵌入式系统中,我们经常要为任务定义堆栈。这些堆栈通常都是uint32类型的数组。你知道为什么要把它们定义成uint32数组,而不能定义成字节数组了吗?

2 结构对齐

2.1 基本长度

为了描述方便,我们定义一个基本长度的概念。一个基本变量的基本长度就是它的长度,一个结构变量的基本长度就是结构成员中基本变量的最大长度。前面说过:在默认情况下,结构变量就是按照其基本长度对齐的。

2.2 对齐

在默认情况下,可以认为结构的成员按照默认方式对齐,即长度为m的基本变量放在mn边界上,其中m=1,2,4或8。因为要把成员对齐,结构的各成员间就可能出现填充字节,结构的大小可能大于各成员大小之和。例如:

typedef struct St1Tag
{
	char ch1;
	int num1;
	short sh1;
	short sh2;
	char ch2;
} St1;

这个结构的基本长度是4,所以这个结构的变量要放在4n边界。成员num1的基本长度为4,所以也要放在4n边界。成员ch1从4n边界开始,只占1个字节,所以在ch1和num1之间有3个填充字节。

在对齐时,编译器会将结构长度取整到基本长度的整数倍。这样以该结构为基本类型的数组既可以连续排列,每个元素又可以对齐放置。所以,sizeof(St1)的值是16,在St1的最后一个成员ch2后面还有3个填充字节。

2.3 紧缩

各编译器都支持结构的紧缩,即连续排列结构的各成员变量,各成员变量之间没有任何填充字节。这时,结构的大小等于各成员变量大小的和。紧缩结构的变量可以放在1n边界,即任意地址边界。

在gcc中可以这样定义紧缩结构:

typedef struct St2Tag
{
	St1 st1;
	char ch2;
}
__attribute__ ((packed)) St2;

armcc是这样的:

typedef __packed struct St2Tag
{
	St1 st1;
	char ch2;
} St2;

VC的写法最麻烦:

#pragma pack(1)
typedef struct St2Tag
{
	St1 st1;
	char ch2;
} St2;
#pragma pack()

如果要同时支持gcc、armcc、VC平台,可以把代码写成这样:

#ifdef __GNUC__
#define GNUC_PACKED	__attribute__ ((packed))
#else
#define GNUC_PACKED
#endif

#ifdef __arm
#define ARM_PACKED	__packed
#else
#define ARM_PACKED
#endif

#ifdef WIN32
#pragma pack(1)
#endif
typedef ARM_PACKED struct St2Tag
{
	St1 st1;
	char ch2;
}
GNUC_PACKED St2;
#ifdef WIN32
#pragma pack()
#endif

其中:__GNUC__是gcc的预定义宏,__arm__是ARM编译器的预定义宏(__arm和__arm__都可以),可以用它们识别当前的编译器。

2.4 全局设置

在VC中,有的程序员习惯设置整个工程的struct member alignment,这对应于命令行选项“/Zpi”,其中i=1,2,4,8,16。如果将这个值设为1,工程中所有结构都是紧缩排列。紧缩排列会增大代码量,降低结构访问效率。我们应该仅在必要的时候使用紧缩结构。

“/Zp1”是紧缩排列,那么“/Zp2”,“/Zp4”等选项是怎样排列的呢?

设选项“/Zpi”中设定的长度是i,设某个结构成员的基本长度是m,则该结构成员按照m和i中较小的值对齐。例如:如果我们设置了“/Zp2”,则基本长度不大于2的成员按照基本长度对齐,基本长度大于2的成员按照2对齐。

其实,我们不应该使用“/Zp2”这么奇怪的选项,除非有非如此不可的理由。

2.5 紧缩结构的用途

其实最常用的结构对齐选项就是:默认对齐和紧缩。在两个程序,或者两个平台之间传递数据时,我们通常会将数据结构设置为紧缩的。这样不仅可以减小通信量,还可以避免对齐带来的麻烦。假设甲乙双方进行跨平台通信,甲方使用了“/Zp2”这么奇怪的对齐选项,而乙方的编译器不支持这种对齐方式,那么乙方就可以理解什么叫欲哭无泪了。

当我们需要一个字节一个字节访问结构数据时,我们通常都会希望结构是紧缩的,这样就不必考虑哪个字节是填充字节了。我们把数据保存到非易失设备时,通常也会采用紧缩结构,既减小存储量,也方便其它程序读出。

2.6 细节

最后记录一个小细节。gcc编译器和VC编译器都支持在紧缩结构中包含非紧缩结构,例如前面例子中的St2可以包含非紧缩的St1。但对于ARM编译器而言,紧缩结构包含的其它结构必须是紧缩的。如果紧缩的St2包含了非紧缩的St1,编译时就会报错:

error:  #1031: Definition of "struct St1Tag" in packed "struct St1T2g" must be __packed
分享到:
评论

相关推荐

    c语言中结构体等在计算机内存的对齐方式

    结构体在计算机内存中的对齐方式 在 C 语言中,结构体(struct)是一种自定义数据类型,用于组合多个变量以便更方便地组织和管理数据。但是,当我们使用 sizeof 运算符来获取结构体的大小时,经常会发现结果与预期...

    带噪音的社交网络对齐数据集.zip

    在社交网络对齐中,噪音可能来源于多种因素:用户输入错误(比如拼写错误、昵称)、隐私设置(部分信息隐藏)、数据缺失,甚至恶意用户制造的虚假信息。处理这些噪音是社交网络对齐的一大挑战,因为它会影响对齐算法...

    谈谈Java中的布局管理器.pdf

    流布局管理器(FlowLayout)是一种常用的布局管理器,将组件逐行定位,行内从左到右,一行排满后换行,默认对齐方式为居中对齐,不改变组件的大小,按组件原有尺寸显示组件。 边界布局管理器(BorderLayout)将整个...

    matlab一种简洁有效的非对齐不完全多视图和缺失多标签学习模型代码.zip

    它不仅处理了多视图学习中的非对齐问题,还解决了多标签数据的缺失问题。NAIM3L模型的核心可能是通过联合优化各个视图的表示和多标签的预测,以达到在数据不完全和不匹配的条件下,仍能有效地学习和预测的效果。 在...

    谈谈Xyrate和希捷技术发展.docx

    标题中的“谈谈Xyrate和希捷技术发展”是指探讨Xyrate公司与希捷科技在存储技术领域的联合进步。Xyrate是一家专注于高性能计算(HPC)存储解决方案的公司,而希捷作为传统磁盘存储的领导者,通过收购Xyrate,增强了其...

    谈谈C51的编程规范

    【谈谈C51的编程规范】 C51是专门针对8051系列单片机的C语言编译器,由于其简洁高效的特点,在单片机编程领域得到了广泛应用。为了提高代码可读性,便于团队协作和问题解决,遵循一定的编程规范显得尤为重要。 一...

    【转】谈谈 JVM 内部锁升级过程(csdn)————程序.pdf

    padding用于内存对齐,以满足内存地址对齐的要求。 当对象被synchronized关键字加锁时,锁的实现机制与对象头中的Mark Word密切相关。在无锁状态下,Mark Word存储的是对象自身的运行时数据,比如哈希码、GC分代...

    结合实例谈谈航拍全景的方法和技巧.docx

    在PTGui中导入照片,自动对齐并创建全景图。如果遇到天空部分缺失的问题,可以利用其他素材在Photoshop中进行补天操作,调整色彩,确保整体的视觉一致性。 3. 分享发布:完成全景图后,可以本地查看或上传至全景...

    C++对象内存分布详解(包括字节对齐和虚函数表)

    内存布局会有一个指向虚基类的指针,接着是派生类的成员,最后是基类的成员,其中基类的成员需要满足自身的对齐规则,但不需要保证整个结构是边界长度的整数倍,因为基类成员已经在派生类中正确对齐了。 总之,理解...

    谈谈步进电机的工作原理

    通过给定子绕组通电,可以产生磁场,从而吸引转子的小齿与之对齐。根据不同的通电顺序,可以使电机按照预定的角度旋转。 例如,对于一个三相反应式步进电机来说,当A相通电时,转子的第1个齿与A相对齐;随后,当B相...

    谈谈一些有趣的CSS话题

    Flexbox擅长处理一维布局,如水平或垂直排列元素,而Grid则在二维布局上表现出色,可以方便地创建响应式、对齐和间隔均匀的网格系统。理解并熟练运用这两种布局模式,能大大提高我们的页面构建效率。 CSS中的伪类和...

    谈谈商业类PPT的制作问题.docx

    5. **细节打磨**: 注重页面中的细节处理,如对齐方式、间距调整等,提升整体美观度。 6. **风格统一**: 整体上保持一致的设计风格,确保观众能够顺畅地跟随演示进程。 #### 五、结论 商业类PPT的制作是一项复杂而...

    flex css5+html5 2.zip

    接下来,我们谈谈HTML5。HTML5是超文本标记语言的最新版本,引入了许多新特性,增强了Web应用的功能和用户体验。一些重要的HTML5特性包括: 1. 新的语义化标签,如`<header>`、`<footer>`、`<article>`和`<section>`...

    结合CSS3的布局新特征谈谈常见布局方法

    CSS(层叠样式表)是用于描述网页表现形式的语言,在网页设计中占据着举足轻重的地位。随着互联网技术的发展,CSS也在不断更新,其中CSS3作为最新版本,为网页布局提供了更多新特性。 在进行前端开发时,页面布局的...

    简单谈谈MySQL中的int(m)

    在设计数据库表结构时,选择合适的`int(m)`显示宽度主要出于两方面的考虑:一是美观,对于有固定格式要求的输出,如报表或用户界面,可以使得数值更对齐;二是如果配合`zerofill`,可以方便地创建顺序编号或其他需要...

    彩色按钮、按钮字体设置程序演示

    接下来,我们谈谈"按钮字体设置"。按钮上的文字是向用户传达操作信息的关键,因此字体的选择、大小、颜色和对齐方式都对可读性和整体美观度有显著影响。这个程序可能提供了字体类型的选择,允许调整字体大小以适应...

    “笔算加减法”练习课(课件).ppt

    总的来说,这堂课旨在通过多样化的练习和游戏,使学生深入理解并熟练掌握笔算加减法的基本步骤和规则,提高他们的计算能力,并通过自我反馈(如“谈谈你这节课的收获吧!”)来促进自我评估和学习反思。

    MyDiskTest

    首先,我们来谈谈连续读写速度。这是衡量U盘传输大文件能力的重要指标。MyDiskTest可以通过大量数据的读写操作,测试U盘在最佳状态下的数据传输速率。高速的连续读写速度意味着用户在转移大文件时可以节省更多时间。...

    manenschijn

    首先,我们可以谈谈字体的分类。常见的字体类型有衬线字体(如Times New Roman)、无衬线字体(如Arial)、手写体和装饰性字体。每种类型的字体都有其特点和适用场景,例如,衬线字体常用于印刷品,而无衬线字体则...

    iOS开发中CAlayer层的属性以及自定义层的方法

    `anchorPoint`,也称为“定位点”或“锚点”,决定了CALayer中哪个点会与`position`指定的位置对齐。它的x、y取值范围都是0到1,默认值为(0.5, 0.5),意味着layer的中心点会与`position`对齐。改变`anchorPoint`...

Global site tag (gtag.js) - Google Analytics