我从这个K& R样本中遗漏了什么?

时间:2011-03-22 20:09:33

标签: c memory

以下是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是最大的类型怎么办 - 它不能以我上面描述的方式工作吗?

由于

5 个答案:

答案 0 :(得分:3)

编译器将调整header的大小,以便可以从ptr数组中的元素有效地检索sizexheader[] 。在大多数体系结构中,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。