是否有一种编程方法来检测您使用的是大端序还是小端序体系结构?我需要能够编写将在英特尔或PPC系统上执行的代码,并使用完全相同的代码(即,没有条件编译)。


当前回答

这是另一个C版本。它定义了一个名为wickd_cast()的宏,用于通过C99联合字面值和非标准__typeof__操作符实现内联类型双关语。

#include <limits.h>

#if UCHAR_MAX == UINT_MAX
#error endianness irrelevant as sizeof(int) == 1
#endif

#define wicked_cast(TYPE, VALUE) \
    (((union { __typeof__(VALUE) src; TYPE dest; }){ .src = VALUE }).dest)

_Bool is_little_endian(void)
{
    return wicked_cast(unsigned char, 1u);
}

如果整数是单字节值,则字节顺序没有意义,并将生成编译时错误。

其他回答

如果你不想要条件编译,你可以写独立的代码。下面是一个例子(摘自Rob Pike):

以独立于端序的方式读取磁盘上以little-endian方式存储的整数:

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

同样的代码,试图考虑到机器的字节顺序:

i = *((int*)data);
#ifdef BIG_ENDIAN
/* swap the bytes */
i = ((i&0xFF)<<24) | (((i>>8)&0xFF)<<16) | (((i>>16)&0xFF)<<8) | (((i>>24)&0xFF)<<0);
#endif
union {
    int i;
    char c[sizeof(int)];
} x;
x.i = 1;
if(x.c[0] == 1)
    printf("little-endian\n");
else
    printf("big-endian\n");

这是另一个解。类似于Andrew Hare的解决方案。

c++的方法是使用Boost,在Boost中,预处理器检查和类型转换被划分到经过非常彻底测试的库中。

Predef库(boost/ Predef .h)识别四种不同的字节序。

end - dian库计划提交给c++标准,支持对end -sensitive数据的各种操作。

正如前面的回答所述,Endianness将成为c++ 20的一部分。

c++20解决方案:

constexpr bool compare(auto const c, auto const ...a) noexcept
{
  return [&]<auto ...I>(std::index_sequence<I...>) noexcept
    {
      return ((std::uint8_t(c >> 8 * I) == a) && ...);
    }(std::make_index_sequence<sizeof...(a)>());
}

static constexpr auto is_big_endian_v{
  compare(std::uint32_t(0x01234567), 0x01, 0x23, 0x45, 0x67)
};

static constexpr auto is_little_endian_v{
  compare(std::uint32_t(0x01234567), 0x67, 0x45, 0x23, 0x01)
};

static constexpr auto is_pdp_endian_v{
  compare(std::uint32_t(0x01234567), 0x23, 0x01, 0x67, 0x45)
};

这个任务可以更容易地完成,但是由于某种原因,<bit>头文件并不总是存在。这是一个演示。

不要使用联合号!

c++不允许通过联合的类型双关语! 从不是最后写入的联合字段读取是未定义的行为! 许多编译器支持这样做作为扩展,但语言不能保证。

更多细节请参见以下答案:

https://stackoverflow.com/a/11996970


只有两个有效的答案可以保证是可移植的。

第一个答案,如果你有一个支持c++ 20的系统, 是从<bit>标头使用std::endian。

C++20 起

constexpr bool is_little_endian = (std::endian::native == std::endian::little);

在c++ 20之前,唯一有效的答案是存储一个整数,然后通过类型双关检查它的第一个字节。 与联合的使用不同,这是c++类型系统明确允许的。

同样重要的是要记住,为了获得最佳的可移植性,应该使用static_cast, 因为reinterpret_cast是实现定义的。

如果程序试图通过非下列类型之一的glvalue访问对象的存储值,则行为未定义: ... char或unsigned char类型。

c++ 11 Onwards

enum class endianness
{
    little = 0,
    big = 1,
};

inline endianness get_system_endianness()
{
    const int value { 0x01 };
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01) ? endianness::little : endianness::big;
}

c++ 11开始(没有enum)

inline bool is_system_little_endian()
{
    const int value { 0x01 };
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01);
}

c++ 98 / c++ 03

inline bool is_system_little_endian()
{
    const int value = 0x01;
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01);
}