我可以为一个工会成员分配一个值,并从另一个工会成员读取相同的值吗? [英] Can I assign a value to one union member and read the same value from another?

查看:83
本文介绍了我可以为一个工会成员分配一个值,并从另一个工会成员读取相同的值吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,我有一个

struct foo {
        /* variable denoting active member of union */
        enum whichmember w;
        union {
                struct some_struct my_struct;
                struct some_struct2 my_struct2;
                struct some_struct3 my_struct3;
                /* let's say that my_struct is the largest member */
        };
};

main()
{
        /*...*/
        /* earlier in main, we get some struct foo d with an */
        /* unknown union assignment; d.w is correct, however */
        struct foo f;
        f.my_struct = d.my_struct; /* mystruct isn't necessarily the */
                                /* active member, but is the biggest */
        f.w = d.w;
        /* code that determines which member is active through f.w */
        /* ... */
        /* we then access the *correct* member that we just found */
        /* say, f.my_struct3 */

        f.my_struct3.some_member_not_in_mystruct = /* something */;
}

通过指针访问C工会成员似乎在说可以通过指针访问成员.查看评论.

Accessing C union members via pointers seems to say that accessing the members via pointers is okay. See comments.

但是我的问题是直接 访问它们.基本上,如果我将所需的所有信息写到工会的最大成员并手动跟踪类型,那么每次访问手动指定的成员仍然会产生正确的信息吗?

But my question concerns directly accessing them. Basically, if I write all the information that I need to the largest member of the union and keep track of types manually, will accessing the manually specified member still yield the correct information every time?

推荐答案

我注意到问题中的代码使用匿名联合,这意味着必须为C11编写它.匿名工会不是C90或C99的一部分.

I note that the code in the question uses an anonymous union, which means that it must be written for C11; anonymous unions were not a part of C90 or C99.

ISO/IEC 9899:2011 的意思是:

§6.5.2.3结构和工会成员

¶3后缀表达式,后跟.运算符和标识符,指定结构或联合对象的成员.该值是命名成员的值, 95),如果第一个表达式是左值,则该值是左值.如果第一个表达式具有限定类型,则结果具有指定成员的类型的限定版本.

§6.5.2.3 Structure and union members

¶3 A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member,95) and is an lvalue if the first expression is an lvalue. If the first expression has qualified type, the result has the so-qualified version of the type of the designated member.

¶4后缀表达式,后跟->运算符和标识符,指定结构或联合对象的成员.该值是第一个表达式指向的对象的命名成员的值,并且是一个左值. 96)如果第一个表达式是指向限定类型​​的指针,则结果为-指定成员类型的限定版本.

¶4 A postfix expression followed by the -> operator and an identifier designates a member of a structure or union object. The value is that of the named member of the object to which the first expression points, and is an lvalue.96) If the first expression is a pointer to a qualified type, the result has the so-qualified version of the type of the designated member.

¶5…

¶6为了简化并集的使用,做出了一项特殊保证:如果一个并集包含几个共享相同初始序列的结构(请参见下文),并且如果并集对象当前包含这些结构之一,则为允许在可以看到联合完成类型声明的任何地方检查其中任何一个的公共初始部分.如果一个或多个初始成员的序列的对应成员具有兼容的类型(对于位域,则具有相同的宽度),则两个结构共享一个公共初始序列.

¶6 One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

95)如果用于读取联合对象的内容的成员与上次用于在该对象中存储值的成员不同,则该对象的对象表示的适当部分值将重新解释为新类型的对象表示形式,如6.2.6中所述(此过程有时称为类型调整").这可能是陷阱的表示形式.

95) If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

96)如果&E是有效的指针表达式(其中&是"address-of"运算符,生成指向其操作数的指针),则表达式E.MOS相同.

96) If &E is a valid pointer expression (where & is the ‘‘address-of’’ operator, which generates a pointer to its operand), the expression (&E)->MOS is the same as E.MOS.

斜体,如标准

Italics as in the standard

第§6.2.6节类型表示说(部分):

And section §6.2.6 Representations of types says (in part):

§6.2.6.1常规

¶6当将值存储在结构或联合类型的对象中(包括成员对象中)时,与任何填充字节相对应的对象表示形式的字节采用未指定的值.( 51)即使结构或联合对象的成员的值可能是陷阱表示,结构或联合对象的值也永远不会是陷阱表示.

§6.2.6.1 General

¶6 When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values.51) The value of a structure or union object is never a trap representation, even though the value of a member of the structure or union object may be a trap representation.

¶7当将值存储在联合类型的对象的成员中时,与该成员不对应但与其他成员对应的对象表示形式的字节采用未指定的值.

¶7 When a value is stored in a member of an object of union type, the bytes of the object representation that do not correspond to that member but do correspond to other members take unspecified values.

51)因此,例如,结构分配不需要复制任何填充位.

51) Thus, for example, structure assignment need not copy any padding bits.


我对您正在执行的操作的解释是脚注51表示可能不起作用",因为您可能只分配了结构的一部分.充其量您只能踩在薄冰上.但是,与此相反,您规定分配的结构(在f.my_struct = d.my_struct;分配中)是最大的成员.不会出错的可能性很高,但是如果两个结构(联合的活动成员和最大的联合成员)中的填充字节位于不同的位置,则可能会出错并如果您向编译器编写者报告了问题,那么编译器编写器只会对您说不违反标准".


My interpretation of what you're doing is that footnote 51 says "it might not work" because you may have assigned only part of the structure. You're treading on thin ice, at best. However, against that, you stipulate that the assigned structure (in the f.my_struct = d.my_struct; assignment) is the largest member. The chances are moderately high that it won't go wrong, but if the padding bytes in the two structures (in the active member of the union and in the largest member of the union) are at different places, then things could go wrong and if you reported a problem to the compiler writer, the compiler writer would simply say to you "don't contravene the standard".

因此,就我是一名语言律师而言,该语言律师的回答是不能保证".在实践中,您不太可能遇到问题,但是有可能,并且您不会卷土重来.

So, to the extent I'm a language lawyer, this language lawyer's answer is "It is not guaranteed". In practice, you're unlikely to run into problems, but the possibility is there and you have no comeback on anyone.

要确保代码安全,只需将f = d;与联合分配一起使用.

To make your code safe, simply use f = d; with a union assignment.

假设计算机要求double对齐在8字节边界上,并且sizeof(double) == 8必须int必须对齐在4字节边界上并且sizeof(int) == 4,并且short必须对齐在2字节边界和sizeof(short) == 2).这是一组合理甚至通用的尺寸和对齐要求.

Suppose that the machine requires double aligned on an 8-byte boundary and sizeof(double) == 8, that int must be aligned on a 4-byte boundary and sizeof(int) == 4, and that short must be aligned on a 2-byte boundary and sizeof(short) == 2). This is a plausible and even common set of sizes and alignment requirements.

进一步,假设您在问题中具有结构的两结构联合变体:

Further, suppose that you have a two-structure union variant of the structure in the question:

struct Type_A { char x; double y; };
struct Type_B { int a; short b; short c; };
enum whichmember { TYPE_A, TYPE_B };

struct foo
{
    enum whichmember w;
    union
    {
        struct Type_A s1;
        struct Type_B s2;
    };
};

现在,在指定的大小和对齐方式下,struct Type_A将占据16个字节,而struct Type_B将占据8个字节,因此并集也将使用16个字节.联合的布局将如下所示:

Now, under the sizes and alignments specified, the struct Type_A will occupy 16 bytes, and struct Type_B will occupy 8 bytes, so the union will use 16 bytes too. The layout of the union will be like this:

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| x | p...a...d...d...i...n...g |               y               |  s1
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|       a       |   b   |   c   |   p...a...d...d...i...n...g   |  s2
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

w元素还意味着struct foo中的(匿名)联合之前有8个字节,其中w可能仅占用4个字节.因此struct foo的大小为24这台机器.不过,这与讨论并不特别相关.

The w element would also mean that there are 8 bytes in struct foo before the (anonymous) union, of which it is likely that w only occupies 4. The size of struct foo is therefore 24 on this machine. That's not particularly relevant to the discussion, though.

现在假设我们有这样的代码:

Now suppose we have code like this:

struct foo d;
d.w = TYPE_B;
d.s2.a = 1234;
d.s2.b = 56;
d.s2.c = 78;

struct foo f;
f.s1 = d.s1;
f.w  = TYPE_B;

现在,根据脚注51的规定,结构分配f.s1 = d.s1;不必复制填充位.我不知道有什么编译器会像这样,但是该标准说编译器不需要复制填充位.这意味着f.s1的值可以是:

Now, under the ruling of footnote 51, the structure assignment f.s1 = d.s1; does not have to copy the padding bits. I know of no compiler that behaves like this, but the standard says that a compiler need not copy the padding bits. That means that the value of f.s1 could be:

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| x | g...a...r...b...a...g...e |   r...u...b...b...i...s...h   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

垃圾是因为不需要复制这7个字节(脚注51表示这是一个选项,即使当前编译器不太可能使用此选项).这是因为d的初始化从来没有在这些字节中设置任何值;这是因为该部分结构的内容未指定.

The garbage is because those 7 bytes need not have been copied (footnote 51 says that is an option, even though it is not likely to be an option exercised by any current compiler). The rubbish is because the initialization of d never set any values in those bytes; the contents of that part of the structure is unspecified.

如果您现在继续尝试将f视为d的副本,您可能会有些惊讶,发现实际上f.s2的8个相关字节中只有1个字节已初始化.

If you now go ahead and try to treat f as a copy of d, you might be a little surprised to find that only 1 byte of the 8 relevant bytes of f.s2 is actually initialized.

我将再次强调:我知道没有编译器可以做到这一点.但是这个问题被标记为语言律师",所以问题是语言标准说明了什么",这是我对标准引用部分的解释.

I'll reemphasize: I know of no compiler that would do this. But the question is tagged 'language lawyer' so the issue is 'what does the language standard state' and this is my interpretation of the quoted sections of the standard.

这篇关于我可以为一个工会成员分配一个值,并从另一个工会成员读取相同的值吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆