该答案基于以下规格(为了清楚起见):
语言:C++ v17,64 位
编译器:g++ v8(GNU 编译器集合https://www.gnu.org/software/gcc/)和 MingW 8.1.0 工具链(https://sourceforge.net/projects/mingw -w64/files/ )
操作系统:Linux Mint & Windows
以下两行代码可用于成功检测处理器的字节顺序:
const uint8_t IsLittleEndian = char (0x0001);
或者
#define IsLittleEndian char (0x0001)
这两个神奇的语句宝石利用了处理器在内存中存储 16 位值的方式。
在“Little Endian”处理器上,如 Intel 和 AMD 芯片组,16 位值以某种[low order/least significant byte][high order/most significant byte]
方式存储(括号表示内存中的一个字节)。
在“Big Endian”处理器上,如 PowerPC、Sun Sparc 和 IBM S/390 芯片组,16 位值以一种[high order/most significant byte][low order/least significant byte]
方式存储。
例如,当我们将 16 位(两个字节)值存储0x1234
到 C++ uint16_t
(在 C++ v11 中定义的类型,以及后来的https://en.cppreference.com/w/cpp/types/integer)中时“Little Endian”处理器上的变量,然后查看存储该值的内存块,您将找到字节序列,[34][12]
.
在“Big Endian 处理器”上,该0x1234
值存储为[12][34]
.
这是一个小演示,可帮助演示各种大小的 C++ 整数变量如何存储在大小端处理器的内存中:
#define __STDC_FORMAT_MACROS // Required for the MingW toolchain
#include <iostream>
#include <inttypes.h>
const uint8_t IsLittleEndian = char (0x0001);
//#define IsLittleEndian char (0x0001)
std::string CurrentEndianMsg;
std::string OppositeEndianMsg;
template <typename IntegerType>
void PrintIntegerDetails(IntegerType IntegerValue)
{
uint16_t SizeOfIntegerValue = sizeof(IntegerValue);
int8_t i;
std::cout << "Integer size (in bytes): " << SizeOfIntegerValue << "\n";
std::cout << "Integer value (Decimal): " << IntegerValue << "\n";
std::cout << "Integer value (Hexidecimal): ";
switch (SizeOfIntegerValue)
{
case 2: printf("0x%04X\n", (unsigned int) IntegerValue);
break;
case 4: printf("0x%08X\n", (unsigned int) IntegerValue);
break;
case 8: printf("0x%016" PRIX64 "\n", (uint64_t) IntegerValue);
break;
}
std::cout << "Integer stored in memory in byte order:\n";
std::cout << " " << CurrentEndianMsg << " processor [current]: ";
for(i = 0; i < SizeOfIntegerValue; i++)https://stackoverflow.com/qhttps://stackoverflow.com/questions/280162/is-there-a-way-to-do-a-c-style-compile-time-assertion-to-determine-machines-e/54175491#54175491uestions/280162/is-there-a-way-to-do-a-c-style-compile-time-assertion-to-determine-machines-e/54175491#54175491
{
printf("%02X ", (((unsigned char*) &IntegerValue)[i]));
}
std::cout << "\n " << OppositeEndianMsg << " processor [simulated]: ";
for(i = SizeOfIntegerValue - 1; i >= 0; i--)
{
printf("%02X ", (((unsigned char*) &IntegerValue)[i]));
}
std::cout << "\n\n";
}
int main()
{
uint16_t ValueUInt16a = 0x0001;
uint16_t ValueUInt16b = 0x1234;
uint32_t ValueUInt32a = 0x00000001;
uint32_t ValueUInt32b = 0x12345678;
uint64_t ValueUInt64a = 0x0000000000000001;
uint64_t ValueUInt64b = 0x123456789ABCDEF0;
std::cout << "Current processor endianness: ";
switch (IsLittleEndian) {
case 0: CurrentEndianMsg = "Big Endian";
OppositeEndianMsg = "Little Endian";
break;
case 1: CurrentEndianMsg = "Little Endian";
OppositeEndianMsg = "Big Endian";
break;
}
std::cout << CurrentEndianMsg << "\n\n";
PrintIntegerDetails(ValueUInt16a);
PrintIntegerDetails(ValueUInt16b);
PrintIntegerDetails(ValueUInt32a);
PrintIntegerDetails(ValueUInt32b);
PrintIntegerDetails(ValueUInt64a);
PrintIntegerDetails(ValueUInt64b);
return 0;
}
这是我机器上演示的输出:
Current processor endianness: Little Endian
Integer size (in bytes): 2
Integer value (Decinal): 1
Integer value (Hexidecimal): 0x0001
Integer stored in memory in byte order:
Little Endian processor [current]: 01 00
Big Endian processor [simulated]: 00 01
Integer size (in bytes): 2
Integer value (Decinal): 4660
Integer value (Hexidecimal): 0x1234
Integer stored in memory in byte order:
Little Endian processor [current]: 34 12
Big Endian processor [simulated]: 12 34
Integer size (in bytes): 4
Integer value (Decinal): 1
Integer value (Hexidecimal): 0x00000001
Integer stored in memory in byte order:
Little Endian processor [current]: 01 00 00 00
Big Endian processor [simulated]: 00 00 00 01
Integer size (in bytes): 4
Integer value (Decinal): 305419896
Integer value (Hexidecimal): 0x12345678
Integer stored in memory in byte order:
Little Endian processor [current]: 78 56 34 12
Big Endian processor [simulated]: 12 34 56 78
Integer size (in bytes): 8
Integer value (Decinal): 1
Integer value (Hexidecimal): 0x0000000000000001
Integer stored in memory in byte order:
Little Endian processor [current]: 01 00 00 00 00 00 00 00
Big Endian processor [simulated]: 00 00 00 00 00 00 00 01
Integer size (in bytes): 8
Integer value (Decinal): 13117684467463790320
Integer value (Hexidecimal): 0x123456789ABCDEF0While the process
Integer stored in memory in byte order:
Little Endian processor [current]: F0 DE BC 9A 78 56 34 12
Big Endian processor [simulated]: 12 34 56 78 9A BC DE F0
我在 Linux Mint 中使用 GNU C++ 工具链编写了这个演示,并且没有办法在其他风格的 C++ 中进行测试,例如 Visual Studio 或 MingW 工具链,所以我不知道在它们中编译需要什么,也不知道我现在可以访问 Windows。
但是,我的一个朋友用 MingW,64 位 (x86_64-8.1.0-release-win32-seh-rt_v6-rev0) 测试了代码,它有错误。经过一番研究,我发现我需要#define __STDC_FORMAT_MACROS
在代码顶部添加一行,以便使用 MingW 进行编译。
现在我们可以直观地看到 16 位值是如何存储在内存中的,让我们看看如何利用它来确定处理器的字节序。
为了在可视化 16 位值在内存中的存储方式方面提供一些额外帮助,让我们看一下下面的图表:
16-Bit Value (Hex): 0x1234
Memory Offset: [00] [01]
---------
Memory Byte Values: [34] [12] <Little Endian>
[12] [34] <Big Endian>
================================================
16-Bit Value (Hex): 0x0001
Memory Offset: [00] [01]
---------
Memory Byte Values: [01] [00] <Little Endian>
[00] [01] <Big Endian>
当我们使用片段将 16 位值0x0001
转换为 char(8 位)时char (0x0001)
,编译器使用 16 位值的第一个内存偏移量作为新值。这是另一个图表,显示了“Little Endian”和“Big Endian”处理器上发生的情况:
Original 16-Bit Value: 0x0001
Stored in memory as: [01][00] <-- Little Endian
[00][01] <-- Big Endian
Truncate to char: [01][xx] <-- Little Endian
[01] Final Result
[00][xx] <-- Big Endian
[00] Final Result
如您所见,我们可以轻松确定处理器的字节顺序。
更新:
我无法在“Big Endian”处理器上测试上面的演示,所以我将代码基于我在网上找到的信息。感谢 MM 指出对我来说显而易见的事情。
我已经更新了演示代码(如下所示)以正确测试字节顺序或处理器。
#define __STDC_FORMAT_MACROS // Required for the MingW toolchain
#include <iostream>
#include <inttypes.h>
std::string CurrentEndianMsg;
std::string OppositeEndianMsg;
template <typename IntegerType>
void PrintIntegerDetails(IntegerType IntegerValue)
{
uint16_t SizeOfIntegerValue = sizeof(IntegerValue);
int8_t i;
std::cout << "Integer size (in bytes): " << SizeOfIntegerValue << "\n";
std::cout << "Integer value (Decimal): " << IntegerValue << "\n";
std::cout << "Integer value (Hexidecimal): ";
switch (SizeOfIntegerValue)
{
case 2: printf("0x%04X\n", (unsigned int) IntegerValue);
break;
case 4: printf("0x%08X\n", (unsigned int) IntegerValue);
break;
case 8: printf("0x%016" PRIX64 "\n", (uint64_t) IntegerValue);
break;
}
std::cout << "Integer stored in memory in byte order:\n";
std::cout << " " << CurrentEndianMsg << " processor [current]: ";
for(i = 0; i < SizeOfIntegerValue; i++)
{
printf("%02X ", (((unsigned char*) &IntegerValue)[i]));
}
std::cout << "\n " << OppositeEndianMsg << " processor [simulated]: ";
for(i = SizeOfIntegerValue - 1; i >= 0; i--)
{
printf("%02X ", (((unsigned char*) &IntegerValue)[i]));
}
std::cout << "\n\n";
}
int main()
{
uint16_t ValueUInt16a = 0x0001;
uint16_t ValueUInt16b = 0x1234;
uint32_t ValueUInt32a = 0x00000001;
uint32_t ValueUInt32b = 0x12345678;
uint64_t ValueUInt64a = 0x0000000000000001;
uint64_t ValueUInt64b = 0x123456789ABCDEF0;
uint16_t EndianTestValue = 0x0001;
uint8_t IsLittleEndian = ((unsigned char*) &EndianTestValue)[0];
std::cout << "Current processor endianness: ";
switch (IsLittleEndian) {
case 0: CurrentEndianMsg = "Big Endian";
OppositeEndianMsg = "Little Endian";
break;
case 1: CurrentEndianMsg = "Little Endian";
OppositeEndianMsg = "Big Endian";
break;
}
std::cout << CurrentEndianMsg << "\n\n";
PrintIntegerDetails(ValueUInt16a);
PrintIntegerDetails(ValueUInt16b);
PrintIntegerDetails(ValueUInt32a);
PrintIntegerDetails(ValueUInt32b);
PrintIntegerDetails(ValueUInt64a);
PrintIntegerDetails(ValueUInt64b);
return 0;
}
这个更新的演示创建了一个 16 位值0x0001
,然后读取变量存储器中的第一个字节。如上面显示的输出所示,在“Little Endian”处理器上,该值将是 0x01。在“Big Endian”处理器上,该值为 0x00。