この回答は、次の仕様に基づいています (これは明確にするためです)。
言語: C++ v17、64 ビット
コンパイラ: g++ v8 (GNU コンパイラ コレクションhttps://www.gnu.org/software/gcc/ ) & MingW 8.1.0 ツールチェーン ( https://sourceforge.net/projects/mingw -w64/files/ )
OS: Linux Mint & Windows
次の 2 行のコードを使用すると、プロセッサのエンディアンを正しく検出できます。
const uint8_t IsLittleEndian = char (0x0001);
また
#define IsLittleEndian char (0x0001)
これら 2 つの小さな魔法のステートメント gem は、プロセッサが 16 ビット値をメモリに格納する方法を利用しています。
Intel や AMD チップセットのような「リトル エンディアン」プロセッサでは、16 ビット値が一定の形式で格納され[low order/least significant byte][high order/most significant byte]
ます (括弧はメモリ内の 1 バイトを表します)。
PowerPC、Sun Sparc、IBM S/390 チップセットなどの「ビッグ エンディアン」プロセッサでは、16 ビット値が一定の形式で格納され[high order/most significant byte][low order/least significant byte]
ます。
たとえば、16 ビット (2 バイト) の値を0x1234
C++ uint16_t
(C++ v11 で定義された型、およびそれ以降はhttps://en.cppreference.com/w/cpp/types/integer )に格納するとします。変数を「リトルエンディアン」プロセッサで使用し、値が格納されているメモリ ブロックを調べると、バイト シーケンス[34][12]
.
「ビッグ エンディアン プロセッサ」では、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++ ツールチェーンを使用してこのデモを作成しましたが、Visual Studio や MingW ツールチェーンなどの他のフレーバーの C++ でテストする手段がありません。現時点で 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>
0x0001
snippet を使用して 16 ビット値を char (8 ビット)に変換するchar (0x0001)
と、コンパイラは新しい値に 16 ビット値の最初のメモリ オフセットを使用します。「リトルエンディアン」プロセッサと「ビッグ エンディアン」プロセッサの両方で何が起こるかを示す別のグラフを次に示します。
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
ご覧のとおり、プロセッサのエンディアンを簡単に判断できます。
アップデート:
「ビッグ エンディアン」プロセッサで上記のデモをテストできないため、Web で見つけた情報に基づいてコードを作成しました。私に明白なことを指摘してくれた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
し、変数メモリの最初のバイトを読み取ります。上記の出力に見られるように、「リトル エンディアン」プロセッサでは、値は 0x01 になります。「ビッグ エンディアン」プロセッサでは、値は 0x00 になります。