以下是K& R的The C Programming Language(第8.7节)中代码示例的摘录:
typedef long Align;
union header {
struct {
union header *ptr;
unsigned size;
} s;
Align x;
};
typedef union header Header;
以下是解释性摘录:
为了简化对齐,所有块都是 标题大小的倍数和 标题正确对齐。这是 由一个包含该联盟的联盟实现 期望的标题结构和 最严格的类型的实例, 我们任意做了很长时间。
因此,据我所知,我们的想法是确保header
实例占用的字节数是sizeof(Align)
的倍数。这个目标对我来说非常有意义。
但考虑long
为64位,int
为32位,指针为64位的情况。在这种情况下,header.s
将是64 + 32 = 96位。因此,sizeof(header)
将是96位,这不是预期的64的倍数。
在这种情况下,我认为有必要将Align
定义为其他内容(也许是double
)。但是我不太确定我是否完全理解什么会决定某个特定架构的选择。它只是“最大”类型吗?如果long
是最大的类型怎么办 - 它不能以我上面描述的方式工作吗?
由于
答案 0 :(得分:3)
编译器将调整header
的大小,以便可以从ptr
数组中的元素有效地检索size
,x
和header[]
。在大多数体系结构中,x
的存在意味着sizeof(header)
将增加到sizeof(long)
的倍数。
答案 1 :(得分:3)
联合的大小至少与其最大成员的大小一样大。因此,即使sizeof(s)
为12且sizeof(long)
为8,如您的示例所示,您仍然会sizeof(header) >= 12
。同样,联合的对齐是其任何成员的最大对齐,因此long
成员的存在确保header
的对齐至少是long
的对齐,在这种情况下将是8。
如果你编译这段代码,你几乎肯定会发现sizeof(header)
是16而不是12.原因是如果你有一个header
对象数组,编译器需要确保任何成员的对齐都是正确的,并且数组连续存储在内存中。为了实现这一点,尺寸需要是对齐的倍数。编译器通过在header
对象的末尾添加额外的4个字节的填充来实现这一点。
答案 2 :(得分:1)
自从我使用结构以来已经很长时间了。但是,我确实使用了它们。主要原则是按成员大小顺序排列成员。
在编写本文时,很长一段时间会对齐最大的寻址边界。我相信情况仍然如此,但我很长时间没有关注硬件问题。设计了一些硬件,除非它们的地址与long的大小一致,否则长时间没有被有效地处理。
我认为目标是标题将在下一个有效的寻址边界上对齐很长时间。这取决于硬件。如果long在32位边界上有效地可寻址,则结构将适当地对齐。如果long只能在64位边界上有效地寻址,那么struct将消耗128位以进行适当的对齐。
答案 3 :(得分:0)
自从我读了K& R书以来,已经很长时间了(太长了),但我相信你是对的。您需要将typedef对齐至少与平台上指针大小相对应的值+ sizeof unsigned。
我的猜测是,当写入(并且最后更新)时,32位操作系统占据了至高无上的地位,并且您的方案逃脱了编写者和编辑者。当然,他们更聪明/更聪明,我和我可能会脱颖而出。
答案 4 :(得分:0)
要正确, sizeof(对齐)必须大于或等于 sizeof(s)。但今天的编译器真的不关心,并为你做好工作。
#include <limits.h>
#include <stdio.h>
typedef long Align;
typedef union header {
struct {
union header *ptr; /* 64 bits */
unsigned size; /* 32 bits */
} s; /* subtotal 96 */
Align x; /* 64 bits -> should be greater than 96 */
} Header; /* total 128 bits */
typedef struct hair {
union header *ptr; /* 64 bits */
unsigned size; /* 32 bits */
} Hair; /* subtotal 96 */
int main(void)
{
Header u;
Hair h;
printf("char %ld bits, %ld bytes\n", sizeof(char)*CHAR_BIT,(sizeof(char)*CHAR_BIT)/8);
printf("unsigned %ld bits, %ld bytes\n", sizeof(unsigned)*CHAR_BIT,(sizeof(unsigned)*CHAR_BIT)/8);
printf("int %ld bits, %ld bytes\n", sizeof(int) * CHAR_BIT, (sizeof(int) * CHAR_BIT)/8);
printf("long int %ld bits, %ld bytes\n", sizeof(long) * CHAR_BIT, (sizeof(long) * CHAR_BIT)/8);
printf("long long int %ld bits, %ld bytes\n", sizeof(long long) * CHAR_BIT, (sizeof(long long) * CHAR_BIT)/8);
printf("float %ld bits, %ld bytes\n", sizeof(float) * CHAR_BIT, (sizeof(float) * CHAR_BIT)/8);
printf("double %ld bits, %ld bytes\n", sizeof(double) * CHAR_BIT, (sizeof(double) * CHAR_BIT)/8);
printf("long double %ld bits, %ld bytes\n\n", sizeof(long double) * CHAR_BIT, (sizeof(long double) * CHAR_BIT)/8);
printf("Header u %ld bits, %ld bytes\n", sizeof(u) * CHAR_BIT, (sizeof(u) * CHAR_BIT)/8);
printf("Header *ptr %ld bits, %ld bytes\n", sizeof(u.s.ptr) * CHAR_BIT, (sizeof(u.s.ptr) * CHAR_BIT)/8);
printf("Header size %ld bits, %ld bytes\n", sizeof(u.s.size) * CHAR_BIT, (sizeof(u.s.size) * CHAR_BIT)/8);
printf("Header x %ld bits, %ld bytes\n\n", sizeof(u.x) * CHAR_BIT, (sizeof(u.x) * CHAR_BIT)/8);
printf("Hair h %ld bits, %ld bytes\n", sizeof(h) * CHAR_BIT, (sizeof(h) * CHAR_BIT)/8);
printf("Hair *ptr %ld bits, %ld bytes\n", sizeof(h.ptr) * CHAR_BIT, (sizeof(h.ptr) * CHAR_BIT)/8);
printf("Hair size %ld bits, %ld bytes\n", sizeof(h.size) * CHAR_BIT, (sizeof(h.size) * CHAR_BIT)/8);
return 0;
}
输出结果为:
$ ./union-limits
char 8 bits, 1 bytes
unsigned 32 bits, 4 bytes
int 32 bits, 4 bytes
long int 64 bits, 8 bytes
long long int 64 bits, 8 bytes
float 32 bits, 4 bytes
double 64 bits, 8 bytes
long double 128 bits, 16 bytes
Header u 128 bits, 16 bytes
Header *ptr 64 bits, 8 bytes
Header size 32 bits, 4 bytes
Header x 64 bits, 8 bytes
Hair h 128 bits, 16 bytes
Hair *ptr 64 bits, 8 bytes
Hair size 32 bits, 4 bytes
如您所见,Hair与Header的大小相同。但是对于不能完成这项工作的编译器,正确的是使用long double作为Align。
保重, BECO。