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


当前回答

不要使用联合号!

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);
}

其他回答

参见Endianness - c级代码说明。

// assuming target architecture is 32-bit = 4-Bytes
enum ENDIANNESS{ LITTLEENDIAN , BIGENDIAN , UNHANDLE };


ENDIANNESS CheckArchEndianalityV1( void )
{
    int Endian = 0x00000001; // assuming target architecture is 32-bit    

    // as Endian = 0x00000001 so MSB (Most Significant Byte) = 0x00 and LSB (Least     Significant Byte) = 0x01
    // casting down to a single byte value LSB discarding higher bytes    

    return (*(char *) &Endian == 0x01) ? LITTLEENDIAN : BIGENDIAN;
} 
int i=1;
char *c=(char*)&i;
bool littleendian=c;

正如Coriiander所指出的,这里的大部分(如果不是全部的话)代码将在编译时被优化掉,因此生成的二进制文件不会在运行时检查“字节顺序”。

据观察,给定的可执行文件不应该以两个不同的字节顺序运行,但我不知道是否总是这样,对我来说,在编译时检查似乎是一种hack。所以我编写了这个函数:

#include <stdint.h>

int* _BE = 0;

int is_big_endian() {
    if (_BE == 0) {
        uint16_t* teste = (uint16_t*)malloc(4);
        *teste = (*teste & 0x01FE) | 0x0100;
        uint8_t teste2 = ((uint8_t*) teste)[0];
        free(teste);
        _BE = (int*)malloc(sizeof(int));
        *_BE = (0x01 == teste2);
    }
    return *_BE;
}

MinGW无法优化这段代码,尽管它确实优化了这里的其他代码。我相信这是因为我保留了分配在较小字节内存上的“随机”值(至少有7位),所以编译器无法知道这个随机值是什么,也不会优化函数。

我还对函数进行了编码,以便只执行一次检查,并为下一次测试存储返回值。

我很惊讶没有人提到预处理器默认定义的宏。但这取决于你的平台;它们比你自己写尾票要干净得多。

例如;如果我们看看GCC定义的内置宏(在x86-64机器上):

:| gcc -dM -E -x c - | grep -i endian

#define __LITTLE_ENDIAN__ 1

在PPC机器上,我得到:

:| gcc -dM -E -x c - | grep -i endian

#define __BIG_ENDIAN__ 1
#define _BIG_ENDIAN 1

(The:| gcc - dm - e -x c - magic打印出所有内置宏。)

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>头文件并不总是存在。这是一个演示。