是否使用了一个联合代替了一个定义好的角色?

ere*_*eOn 13 c++ standards endianness unions

今天早上我和一位同事讨论了关于检测字节序的"编码技巧"的正确性.

诀窍是:

bool is_big_endian()
{
  union
  {
    int i;
    char c[sizeof(int)];
  } foo;


  foo.i = 1;
  return (foo.c[0] == 1);
}
Run Code Online (Sandbox Code Playgroud)

对我来说,似乎这种用法union是不正确的,因为设置联合的一个成员并读取另一个成员的定义并不明确.但我必须承认,这只是一种感觉,我缺乏实际的证据来强化我的观点.

这个技巧是否正确?谁在这?

Pra*_*rav 11

您的代码不可移植.它可能适用于某些编译器,也可能不适用.

当您尝试访问联合的非活动成员时,您对于未定义的行为是正确的[就像给出的代码一样]

$ 9.5/1

在联合中,最多一个数据成员可以在任何时间处于活动状态,也就是说,最多一个数据成员的值可以随时存储在并集中.

所以foo.c[0] == 1不正确,因为c那时不活跃.如果你认为我错了,请随意纠正我.

  • @Matthieu M.:这就是我认为相关的这个上下文$ 9.5`"在一个联盟中,最多一个数据成员可以随时活动,也就是说,最多一个数据成员的值可以可以随时存储在一个联合中."`试图访问联合的非活动成员会导致未定义的行为. (6认同)
  • @drhirsch:有很好的定义,然后有明确的定义.就标准而言,行为是不确定的.当然,个别编制者可以提供额外的保证. (5认同)
  • 我找不到C++ 0x标准中的引用,我找到了一个部分解除了对struct A {int a; char b; ``struct B {int a; 双c; ``union U {A a; B b; `并且说访问`uaa`或`uba`总是可能的(因为它是A和B的公共前缀序列)但是没有关于undefinedness的内容:/ (2认同)
  • 由于各种可移植性问题,MISRA-C标准禁止了工会,主要涉及对齐和填充.例如,他们禁止使用"变体".但是,它们对规则提出了一个例外,并允许联合使用一个char数组进行数据打包,其大小与联合中的其他数据类型相同.这是有道理的,因为_data打包可能是C/C++语言中union关键字唯一合理的用法.如果这将是未定义的行为,那将有效地使工会无用.如果是这种情况,应该将它们从语言中删除. (2认同)

moo*_*eep 5

不要这样做,更好地使用以下内容:

#include <arpa/inet.h>
//#include <winsock2.h> // <-- for Windows use this instead

#include <stdint.h>

bool is_big_endian() {
  uint32_t i = 1;
  return i == htonl(i);
}
Run Code Online (Sandbox Code Playgroud)

说明:

htonl函数将u_long从主机转换为TCP/IP网络字节顺序(这是big-endian).


参考文献: