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

时间:2011-05-26 08:57:39

标签: c++ standards endianness unions

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

诀窍是:

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


  foo.i = 1;
  return (foo.c[0] == 1);
}

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

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

5 个答案:

答案 0 :(得分:11)

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

当你试图访问union的非活动成员时,你是正确的行为是正确的[就像给出的代码一样]

$ 9.5 / 1

  

在联盟中,最多其中一个数据成员可以随时处于活动状态,也就是说,最多一个数据成员的值可以随时存储在一个联合中

因此foo.c[0] == 1不正确,因为此时c未处于活动状态。如果你认为我错了,请随意纠正我。

答案 1 :(得分: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);
}

说明:

  

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


参考文献:

答案 2 :(得分:2)

你认为该代码没有明确定义的行为是正确的。以下是如何移植:

#include <cstring>

bool is_big_endian()
{
    static unsigned const i = 1u;
    char c[sizeof(unsigned)] = { };
    std::memcpy(c, &i, sizeof(c));
    return !c[0];
}

// or, alternatively

bool is_big_endian()
{
    static unsigned const i = 1u;
    return !*static_cast<char const*>(static_cast<void const*>(&i));
}

答案 3 :(得分:0)

该函数应命名为is_little_endian。我想你可以使用这个联合技巧。或者也可以演员表演。

答案 4 :(得分:0)

代码有未定义的行为,尽管有些(大多数?)编译器会 定义它,至少在有限的情况下。

标准的意图reinterpret_cast用于 这个。然而,自标准以来,这种意图并未得到很好的表达 无法真正定义行为;当时没有定义它的愿望 硬件不支持它(例如由于对齐问题)。和 很明显,你不能只在{两个}之间reinterpret_cast 任意类型,并希望它工作。

从实施质量的角度来看,我希望两者都有 union技巧和reinterpret_cast工作,如果 unionreinterpret_cast位于同一功能块中; union应该 只要编译器可以看到最终类型是union (虽然我使用的编译器并非如此)。