【问题标题】:Finding endian-ness programmatically at compile-time using C++11使用 C++11 在编译时以编程方式查找字节序
【发布时间】:2017-02-07 09:13:44
【问题描述】:

我在 SO 中提到了很多关于这个主题的问题,但到目前为止找不到任何解决方案。这里提到了一种自然的解决方案:Determining endianness at compile time.
但是,cmets中提到的相关问题&相同的答案。

经过一些修改,我可以使用 g++ 和 clang++ (-std=c++11) 编译类似的解决方案,而不会发出任何警告。

static_assert(sizeof(char) == 1, "sizeof(char) != 1");
union U1
{
  int i;
  char c[sizeof(int)];
};  
union U2
{ 
  char c[sizeof(int)];
  int i;
};  

constexpr U1 u1 = {1};
constexpr U2 u2 = {{1}};
constexpr bool IsLittleEndian ()
{ 
  return u1.i == u2.c[0];  // ignore different type comparison
}   

static_assert(IsLittleEndian(), "The machine is BIG endian");

Demo.

这可以被认为是确定字节序的确定性方法还是错过了类型双关或其他什么?

【问题讨论】:

  • uint8_t(u2.i) 不会在任一字节序上产生相同的值吗?强制转换应该是保值的,而不仅仅是选择第一个字节。
  • 一个 4 字节整数中有 24 种可能的字节顺序。 至少三个已被真正的计算机使用。此外,不完全清楚授予 [[un]signed] char 的严格别名规则的例外适用于 uint8_t
  • 我相信如果你真的在大端机器上运行它,它仍然会测试1 == 1并返回true
  • sizeof(char) == 1 根据定义为真。 sizeofchar 的单位给出, 所以这个断言实际上永远不会失败。

标签: c++ c++11 endianness compile-time type-punning


【解决方案1】:

从 C++20 开始,您可以使用来自 <type_traits> 标头的 std::endian

#include <type_traits>

int main()
{
    static_assert(std::endian::native==std::endian::big,
                  "Not a big endian platform!");
}

See it live

【讨论】:

  • 你来自未来吗?
【解决方案2】:

您的尝试与这个明显不起作用的尝试没有什么不同(其中IsLittleEndian()true 相同):

constexpr char c[sizeof(int)] = {1};
constexpr int i = {1};
constexpr bool IsLittleEndian ()
{ 
  return i == c[0];  // ignore different type comparison
}   

static_assert(IsLittleEndian(), "The machine is BIG endian");

我相信 C++11 没有提供在编译期间以编程方式确定目标平台字节序的方法。我的论点是在运行时执行该检查的唯一有效方法是使用unsigned char 指针检查int 变量(因为其他类型双关语不可避免地包含未定义的行为):

const uint32_t i = 0xffff0000;

bool isLittleEndian() {
    return 0 == *reinterpret_cast<const unsigned char*>(&i);
}

C++11 不允许创建此函数constexpr,因此无法在编译时执行此检查。

【讨论】:

  • 您能否更详细地解释一下为什么尝试的解决方案不起作用?或者为什么它与您在答案开始时提到的(非工作)相同。我没有机会检查大端机器,但我认为你说的是​​真的。但问题是为什么?
  • @iammilind 工会在您的“解决方案”中服务的目的是什么?你永远不会访问/使用U1::c,也永远不会访问/使用U2::i。因此,在消除它们之后,我们得到了我的版本。
  • 2 个联合只是为了消除编译器错误,否则 1 个联合会带来编译器错误。如果您检查u1.i == u1.c[0]u2 相同),那么它工作正常。此解决方案在 SO 中的许多其他答案中。但这些仅限于运行时。由于constexpr 的限制,它们无法在编译时工作。这里 U1 和 U2 互为镜像。我试图欺骗编译器以允许它进行编译。可能是错的。但是如果有人用大端检查它就好了。
  • @iammilind:我理解U2 u2 = {{1}} 中初始化的方式是它总是将数组的第一项设置为1。不是吗?
  • 顺便说一句,C++ 20 终于解决了这个问题:en.cppreference.com/w/cpp/types/endian
猜你喜欢
  • 1970-01-01
  • 2012-12-12
  • 2010-11-03
  • 2012-10-18
  • 2020-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多