简体   繁体   English

C struct元素对齐(ansi)

[英]C struct elements alignment (ansi)

just a simple question... what the standard says about the structure members alignment? 只是一个简单的问题......关于结构成员对齐的标准是什么? for example with this one: 例如,这个:

struct
{
    uint8_t a;
    uint8_t b;
    /* other members */
} test;

It is guarateed that b is at offset 1 from the struct start? 保证b与struct start的偏移量为1? Thanks 谢谢

The standard (as of C99) doesn't really say anything. 标准(截至C99)并没有真正说什么。

The only real guarantees are that (void *)&test == (void *)&a , and that a is at a lower address than b . 唯一的真正的保证是(void *)&test == (void *)&a ,以及a处于比低位地址b Everything else is up to the implementation. 其他一切都取决于实施。

C11 6.7.2.1 Structure and union specifiers p14 says C11 6.7.2.1结构和联合说明符 p14表示

Each non-bit-field member of a structure or union object is aligned in an implementation- defined manner appropriate to its type. 结构或联合对象的每个非位字段成员以适合其类型的实现定义方式对齐。

meaning that you can't make any portable assumptions about the difference between the addresses of a and b . 这意味着您无法对ab的地址之间的差异做出任何可移植的假设。

It should be possible to use offsetof to determine the offset of members. 应该可以使用offsetof来确定成员的偏移量。

For C the alignment is implementation defined, we can see that in the draft C99 standard section 6.7.2.1 Structure and union specifiers paragraph 12 (In C11 it would be paragraph 14) which says: 对于C,对齐是实现定义的,我们可以看到在草案C99标准部分6.7.2.1 结构和联合说明符12段(在C11中它将是第14段)中说:

Each non-bit-field member of a structure or union object is aligned in an implementation defined manner appropriate to its type. 结构或联合对象的每个非位字段成员以适合其类型的实现定义方式对齐。

and paragraph 13 says: 13段说:

Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. 在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址。 A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. 指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。 There may be unnamed padding within a structure object, but not at its beginning. 结构对象中可能存在未命名的填充,但不是在其开头。

and for C++ we have the following similar quotes from the draft standard section 9.2 Class members paragraph 13 says: 对于C ++,我们从草案标准第9.2节中得到以下类似的引用。 类成员13段说:

Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. 分配具有相同访问控制(第11条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。 The order of allocation of non-static data members with different access control is unspecified (Clause 11). 具有不同访问控制的非静态数据成员的分配顺序未指定(第11条)。 Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; 实施对齐要求可能导致两个相邻成员不能立即分配;

and paragraph 19 says: 19段说:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. 指向标准布局结构对象的指针(使用reinterpret_cast进行适当转换)指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。 [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. [注意:因此,在标准布局结构对象中可能存在未命名的填充,但不是在其开头,以实现适当的对齐。 —end note ] - 尾注]

the case you're using is not really an edge case, both uint_8 are small enough to fit in the same word in memory and it would be no use to put each uint_8 in a uint_16. 你正在使用的情况并不是一个边缘情况,uint_8都足够小,可以放在内存中的同一个单词中,将每个uint_8放在uint_16中都没用。

A more critical case would be something like : 一个更关键的案例是:

{
    uint8_t a;
    uint8_t b;

    uint_32 c; // where is C, at &a+2 or &a+4 ?
    /* other members */
} test;

and anyway this will always depend on the target architecture and your compiler... 无论如何,这将始终取决于目标架构和您的编译器......

K&R second edition (ANSI C) in chapter 6.4 (page 138) says: 第6.4章(第138页)中的K&R第二版(ANSI C)说:

Don't assume, however, that the size of a structure is the sum of the sizes of its memebers. 但是,不要认为结构的大小是其成员大小的总和。 Because of alignment requirements for different objects, there may be unnamed "holes" in a structure. 由于不同对象的对齐要求,结构中可能存在未命名的“洞”。

So no, ANSI C does not guarantee that b is at offset 1. 所以不,ANSI C不保证b偏移量为1。

It is even likely that the compiler puts b at offset sizeof(int) so that it's aligned on the size of a machine word, which is easier to deal with. 甚至可能是编译器将b放在偏移量sizeof(int)以便它与机器字的大小对齐,这更容易处理。

Some compilers support pack-pragmas so that you can force that there are no such "holes" in the struct , but that is not portable. 一些编译器支持pack-pragma,这样你就可以强制struct中没有这样的“漏洞”,但这不是可移植的。

What is guaranteed by the C-Standard already had been mentioned by other answers. 其他答案已经提到了C-Standard所保证的内容。

However, to make sure b is at offset 1 your compiler might offer options to "pack" the structure, will say to explicitly add no padding. 但是,为了确保b 偏移1编译器可能会提供选项,以“包”的结构,会说明确添加没有填充。

For gcc this can be achieved by the #pragma pack() . 对于gcc,这可以通过#pragma pack()来实现。

#pragma pack(1)
struct
{
  uint8_t a; /* Guaranteed to be at offset 0. */
  uint8_t b; /* Guaranteed to be at offset 1. */
  /* other members are guaranteed to start at offset 2. */
} test_packed;
#pragma pack()

struct
{
  uint8_t a; /* Guaranteed to by at offset 0. */
  uint8_t b; /* NOT guaranteed to be at offset 1. */
  /* other members are NOT guaranteed to start at offset 2. */
} test_unpacked;

A portable (and save) solution would be to simply use an array: 便携式(和保存)解决方案是简单地使用数组:

struct
{
  uint8_t ab[2]; /* ab[0] is guaranteed to be at offset 0. */
                 /* ab[1] is guaranteed to be at offset 1. */
  /* other members are NOT guaranteed to start at offset 2. */
} test_packed;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM