是否有一种编程方法来检测您使用的是大端序还是小端序体系结构?我需要能够编写将在英特尔或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 num = 1; If (*(char *)&num == 1) { printf (" \ nLittle-Endian \ n "); } 其他的 { printf(“大端\ n”); }

除非你使用的框架已经移植到PPC和英特尔处理器上,否则你将不得不进行条件编译,因为PPC和英特尔平台拥有完全不同的硬件架构、管道、总线等。这使得两者的程序集代码完全不同。

至于查找字节序,请执行以下操作:

short temp = 0x1234;
char* tempChar = (char*)&temp;

您可以让tempChar为0x12或0x34,从中可以知道字节序。

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编译器的工作方式(至少我知道的每个人)必须在编译时决定字节序。即使对于双端处理器(如ARM和MIPS),您也必须在编译时选择字节顺序。

此外,对于可执行文件(如ELF),在所有通用文件格式中都定义了字节顺序。虽然可以编写二进制的编码器代码(可能是为了ARM服务器的漏洞?),但它可能必须在汇编中完成。