c – Cast一个原始类型的指针到A结构指针 – 对齐和填充?
只要20分钟,当我回答一个问题,我想出了一个有趣的场景,我不知道的行为:
让我有一个大小为n的整数数组,由intPtr指向; int* intPtr; 让我也有一个这样的结构: typedef struct { int val1; int val2; //and less or more integer declarations goes on like this(not any other type) }intStruct; 我的问题是如果我做一个cast intStruct * structPtr =(intStruct *)intPtr; 如果我遍历结构体的元素,我确定要正确地获取每个元素吗?任何架构/编译器中是否存在错误对齐的可能性(可能由于填充)) 解决方法
该标准是相当具体的,即使是一个POD-struct(也就是我认为最严格的结构类)可以在成员之间填充. (“因此在POD-struct对象中可能会有未命名的填充,而不是在开始的时候,为了实现适当的对齐,这是必需的.” – 一个非规范性的注释,但是仍然意图很清楚).
例如,对比标准布局结构的要求(C 11,§1.8 / 4):
…与数组(§8.3.4/ 1):
在数组中,元素本身需要连续分配,而在结构中,只有存储需要是连续的. 可能使“连续存储”要求更有意义的第三种可能性是考虑一个不是简单的可复制或标准布局的结构体/类.在这种情况下,存储可能根本不可能是连续的.例如,一个实现可能会放置一个用于保存所有私有变量的内存区域,以及一个完全独立的内存区域来保存所有公共变量.为了使这一点更具体,考虑两个定义,如: class A { int a; public: int b; } a; class B { int x; public: int y; } b; 有了这些定义,内存可能会被布置成: a.a; b.x; // ... somewhere else in memory entirely: a.b; b.y; 在这种情况下,元素和存储都不需要连续,因此可以允许完全独立的结构体/类的交织部分. 也就是说,第一个元素必须与整个结构体的地址相同(9.2 / 17):“使用reinterpret_cast适当转换的指向POD-struct对象的指针指向其初始成员(或者如果该成员是一个位域,然后到它所在的单位),反之亦然. 在你的情况下,你有一个POD结构,所以(§9.2/ 17):“指向一个POD-struct对象的指针,使用reinterpret_cast适当地转换,指向它的初始成员(或者如果该成员是一个位字段,反之亦然.由于第一个成员必须对齐,而其余的成员都是相同的类型,因此在其他成员之间的填充是绝对必要的(即,除了位字段之外,你可以把任何类型放在一个结构体中)也可以放在一个数组中,其中需要连续分配元素).如果您的单词小于单词面向机器(例如早期DEC Alphas),那么填充可能会使访问变得更简单.例如,早期DEC Alphas(在硬件级别)只能一次读/写一个完整的(64位)字.因此,让我们考虑一下四个char元素的结构: struct foo { char a,b,c,d; }; 如果需要将它们放在内存中以使它们相邻,则访问foo :: b(例如)将要求CPU加载该字,然后将其移位8位,然后将其掩码为零扩展该字节填写整个注册表. 存储将更糟糕 – CPU将必须加载整个字的当前值,掩盖当前适当的字符大小的内容,将新值移动到正确的位置,或将其更改为字,最后存储结果. 相比之下,通过元素间的填充,这些元素中的每一个都成为简单的加载/存储,没有移位,掩蔽等. 至少如果内存服务,DEC的Alpha的正常编译器,int是32位,长度是64位(早于long long).因此,使用四个int的结构,您可以预期在元素之间再次看到32位的填充(以及最后一个元素之后的另外32位). 考虑到你有一个POD结构,你仍然有一些可能性.我可能会喜欢的是使用offsetof获取结构体的成员的偏移量,创建它们的数组,并通过这些偏移访问成员.我在previous answers的couple中展示了如何做到这一点. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |