I have the following type:
我有以下类型:
union {
struct {
uint32_t c0;
uint32_t k0[4];
uint32_t c1;
uint32_t v[2];
uint32_t i[2];
uint32_t c2;
uint32_t k1[4];
uint32_t c3;
} named;
uint32_t array[16];
} state;
because each field inside "named" has a meaning upon initialization, but I will use it mostly as a word array after that. Does C guarantees that state.array[0]
is the same as state.named.c0
, state.array[1]
is state.named.k0[0]
and so on?
因为“named”内的每个字段在初始化时都有意义,但我将主要使用它作为后面的单词数组。C保证那个状态。数组[0]与state.name .c0, state相同。数组[1]是state。name。k0[0]等等?
If not, how likely is it to work? Are there any compiler/platform that break my code if I rely on it?
如果没有,它工作的可能性有多大?如果我依赖它,是否有编译器/平台会破坏我的代码?
3 个解决方案
#1
3
To answer your most worrisome question, "..how likely is it to work", don't gamble on likelihood unless it is a sure thing. It isn't in this case.
来回答你最令人担忧的问题。不要指望可能性,除非它是确定的。在这种情况下不是这样的。
The standard (§6.7.2.1,p15) dictates the address of the first member of a struct, or of all members of a union, is the same as of the struct or union itself. For you this only means the address of array[16]
and named
are identical, and both are equivalent to the address of state
. However, without implementation-dependent packing, there is no guarantee that the struct will overlay precisely, as the same section of the standard calls out that inter-structure packing is possible.
标准(§6.7.2.1 p15)规定的地址的第一个成员结构、或联盟的所有成员,是一样的结构或工会本身。对于您来说,这仅仅意味着数组[16]和命名的地址是相同的,并且两者都等价于状态的地址。然而,如果没有依赖于实现的包装,就不能保证结构体会精确地覆盖,因为标准的同一部分指出,结构间包装是可能的。
For example, for whatever reason a compiler working with a packing scheme to always start members on 64bit boundaries could lay out your name
as follows:
例如,无论出于什么原因,使用包装方案的编译器总是在64位边界上启动成员,可以列出您的名称如下:
struct {
uint32_t c0;
**padding 4 bytes**
uint32_t k0[4];
uint32_t c1;
**padding 4 bytes**
uint32_t v[2];
uint32_t i[2];
uint32_t c2;
**padding 4 bytes**
uint32_t k1[4];
uint32_t c3;
**padding 4 bytes**
} name;
In short, all you are guaranteed is that the memory occupied by name
as a whole and the memory occupied by the other member of your union, array[16]
shall occupy the same memory, starting at the beginning addressable location of each. What that memory looks like under the covers of name
's packing is up to the implementation and any packing hints you care to supply.
简而言之,你所能保证的是,所有的内存被命名为一个整体,而你的另一个成员所占用的内存,数组[16]将占据相同的内存,从开始的可寻址位置开始。在名称的包装下面的记忆是什么样的,取决于执行和任何包装提示您关心的供应。
Some of the relevant portions of the standard:
标准的一些相关部分:
C99-§6.7.2.1,p6 As discussed in 6.2.5, a structure is a type consisting of a sequence of members, whose storage is allocated in an ordered sequence, and a union is a type consisting of a sequence of members whose storage overlap.
C99——§6.7.2.1,p6 6.2.5中讨论的一个结构类型的成员组成的一个序列,在一个有序序列的存储分配,工会是一个类型的成员组成的一个序列存储重叠。
C99-§6.7.2.1,p15 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.
C99——§6.7.2.1 p15在结构对象,non-bit-field成员和位域驻留的单位地址,增加他们声明的顺序。一个指向结构对象的指针,经过适当的转换,指向它的初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在它的开始。
C99-§6.7.2.1,p16 The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.
C99——§6.7.2.1,p16联盟的大小足以包含最大的成员。最多一个成员的值可以随时存储在union对象中。一个指向联合对象的指针,适当地转换后,指向它的每个成员(或者如果一个成员是位域,那么指向它所在的单元),反之亦然。
C99-§6.7.2.1,p17 There may be unnamed padding at the end of a structure or union.
C99——§6.7.2.1,p17年底可能会有不知名的填充一个结构或联盟。
#2
2
From the C Standard:
从C标准:
6.7.2.1/15
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.6.7.2.1/15在结构对象中,非位域成员和位域所在的单元具有按声明顺序增加的地址。一个指向结构对象的指针,适当地转换后,指向它的初始成员(或者如果该成员是位域,那么指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在它的开始。
6.7.2.1/16
The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.6.7.2.1/16一个联盟的规模足以容纳其最大的成员。最多一个成员的值可以随时存储在union对象中。一个指向联合对象的指针,适当地转换后,指向它的每个成员(或者如果一个成员是位域,那么指向它所在的单元),反之亦然。
Emphasis mine. This basically translates into state.named
, state.named.c0
, and state.array
having the same address. However, and here's the catch, there is no guarantee about where the rest of named
's members lie (order in memory is specified, but location is not). There can, technically, be padding in between each of named
's members (and even at the end of named
as well). So the answer is no, that is not guaranteed. Padding can be added in between your members.
我特别强调。这基本上转换为状态。命名,状态。名称。c0,和状态。具有相同地址的数组。但是,这里有一个问题,不能保证命名成员的其他位置(指定内存中的顺序,但不确定位置)。在技术上,可以在每个命名成员之间填充(甚至在命名末尾也可以)。所以答案是否定的,这是不确定的。可以在成员之间添加填充。
The key is the last sentence of the first quote:
关键是第一句引文的最后一句话:
There may be unnamed padding within a structure object
结构对象中可能有未命名的填充
#3
-3
yes state.array[0]
is same as state.named.c0
. C guarantees that 'array[16]` and structure named would occupy same area of memory.
是的状态。数组[0]与state.name .c0相同。C保证'array[16] '和命名的结构将占用相同的内存区域。
This is true as long as data type are matching. for e.g if you are storing 2 sorts and then read a integer the result is machine dependent.
这是正确的,只要数据类型是匹配的。为e。如果你存储2种类型,然后读取一个整数,结果就是机器依赖。
#1
3
To answer your most worrisome question, "..how likely is it to work", don't gamble on likelihood unless it is a sure thing. It isn't in this case.
来回答你最令人担忧的问题。不要指望可能性,除非它是确定的。在这种情况下不是这样的。
The standard (§6.7.2.1,p15) dictates the address of the first member of a struct, or of all members of a union, is the same as of the struct or union itself. For you this only means the address of array[16]
and named
are identical, and both are equivalent to the address of state
. However, without implementation-dependent packing, there is no guarantee that the struct will overlay precisely, as the same section of the standard calls out that inter-structure packing is possible.
标准(§6.7.2.1 p15)规定的地址的第一个成员结构、或联盟的所有成员,是一样的结构或工会本身。对于您来说,这仅仅意味着数组[16]和命名的地址是相同的,并且两者都等价于状态的地址。然而,如果没有依赖于实现的包装,就不能保证结构体会精确地覆盖,因为标准的同一部分指出,结构间包装是可能的。
For example, for whatever reason a compiler working with a packing scheme to always start members on 64bit boundaries could lay out your name
as follows:
例如,无论出于什么原因,使用包装方案的编译器总是在64位边界上启动成员,可以列出您的名称如下:
struct {
uint32_t c0;
**padding 4 bytes**
uint32_t k0[4];
uint32_t c1;
**padding 4 bytes**
uint32_t v[2];
uint32_t i[2];
uint32_t c2;
**padding 4 bytes**
uint32_t k1[4];
uint32_t c3;
**padding 4 bytes**
} name;
In short, all you are guaranteed is that the memory occupied by name
as a whole and the memory occupied by the other member of your union, array[16]
shall occupy the same memory, starting at the beginning addressable location of each. What that memory looks like under the covers of name
's packing is up to the implementation and any packing hints you care to supply.
简而言之,你所能保证的是,所有的内存被命名为一个整体,而你的另一个成员所占用的内存,数组[16]将占据相同的内存,从开始的可寻址位置开始。在名称的包装下面的记忆是什么样的,取决于执行和任何包装提示您关心的供应。
Some of the relevant portions of the standard:
标准的一些相关部分:
C99-§6.7.2.1,p6 As discussed in 6.2.5, a structure is a type consisting of a sequence of members, whose storage is allocated in an ordered sequence, and a union is a type consisting of a sequence of members whose storage overlap.
C99——§6.7.2.1,p6 6.2.5中讨论的一个结构类型的成员组成的一个序列,在一个有序序列的存储分配,工会是一个类型的成员组成的一个序列存储重叠。
C99-§6.7.2.1,p15 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.
C99——§6.7.2.1 p15在结构对象,non-bit-field成员和位域驻留的单位地址,增加他们声明的顺序。一个指向结构对象的指针,经过适当的转换,指向它的初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在它的开始。
C99-§6.7.2.1,p16 The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.
C99——§6.7.2.1,p16联盟的大小足以包含最大的成员。最多一个成员的值可以随时存储在union对象中。一个指向联合对象的指针,适当地转换后,指向它的每个成员(或者如果一个成员是位域,那么指向它所在的单元),反之亦然。
C99-§6.7.2.1,p17 There may be unnamed padding at the end of a structure or union.
C99——§6.7.2.1,p17年底可能会有不知名的填充一个结构或联盟。
#2
2
From the C Standard:
从C标准:
6.7.2.1/15
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.6.7.2.1/15在结构对象中,非位域成员和位域所在的单元具有按声明顺序增加的地址。一个指向结构对象的指针,适当地转换后,指向它的初始成员(或者如果该成员是位域,那么指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在它的开始。
6.7.2.1/16
The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bit- field, then to the unit in which it resides), and vice versa.6.7.2.1/16一个联盟的规模足以容纳其最大的成员。最多一个成员的值可以随时存储在union对象中。一个指向联合对象的指针,适当地转换后,指向它的每个成员(或者如果一个成员是位域,那么指向它所在的单元),反之亦然。
Emphasis mine. This basically translates into state.named
, state.named.c0
, and state.array
having the same address. However, and here's the catch, there is no guarantee about where the rest of named
's members lie (order in memory is specified, but location is not). There can, technically, be padding in between each of named
's members (and even at the end of named
as well). So the answer is no, that is not guaranteed. Padding can be added in between your members.
我特别强调。这基本上转换为状态。命名,状态。名称。c0,和状态。具有相同地址的数组。但是,这里有一个问题,不能保证命名成员的其他位置(指定内存中的顺序,但不确定位置)。在技术上,可以在每个命名成员之间填充(甚至在命名末尾也可以)。所以答案是否定的,这是不确定的。可以在成员之间添加填充。
The key is the last sentence of the first quote:
关键是第一句引文的最后一句话:
There may be unnamed padding within a structure object
结构对象中可能有未命名的填充
#3
-3
yes state.array[0]
is same as state.named.c0
. C guarantees that 'array[16]` and structure named would occupy same area of memory.
是的状态。数组[0]与state.name .c0相同。C保证'array[16] '和命名的结构将占用相同的内存区域。
This is true as long as data type are matching. for e.g if you are storing 2 sorts and then read a integer the result is machine dependent.
这是正确的,只要数据类型是匹配的。为e。如果你存储2种类型,然后读取一个整数,结果就是机器依赖。