Этот ответ основан на следующих спецификациях (это для ясности):
Язык: C ++ v17, 64-битный
Компиляторы: g ++ v8 (Набор инструментов GNU Compiler Collection 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/q/150167/est-li-sposob-sdelat-utverzhdenie-vo-vremya-kompilyatsii-v-stile-c-chtoby-opredelit-poryadkovyi-nomer-mashinyuestions/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
Я написал эту демонстрацию с помощью инструментария GNU C ++ в Linux Mint, и у меня нет средств для тестирования в других разновидностях 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
в символ (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
Как видите, мы можем легко определить порядковый номер процессора.
UPDATE:
Я не могу протестировать приведенную выше демонстрацию на процессоре "Big Endian", поэтому я основал код на информации, которую нашел в Интернете. Спасибо М.М за указание на очевидное для меня.
Я обновил демонстрационный код (как показано ниже), чтобы проверить правильность порядка байтов или процессора.
#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.