10 ответов:
это для проверки времени компиляции
вы можете использовать информацию из файла заголовка boost
endian.hpp, который охватывает множество платформ.редактировать для проверки во время выполнения
bool isLittleEndian() { short int number = 0x1; char *numPtr = (char*)&number; return (numPtr[0] == 1); }создайте целое число и прочитайте его первый байт (наименее значимый байт). Если этот байт равен 1, то система является обратным порядком байтов, в противном случае это большой endian.
редактировать думал о
да вы можете столкнуться с потенциальной проблемой на некоторых платформах (не могу придумать), где
sizeof(char) == sizeof(short int). Вы можете использовать многобайтовые интегральные типы фиксированной ширины, доступные в<stdint.h>, или если ваша платформа не имеет его, снова вы можете адаптировать заголовок boost для вашего использования:stdint.hpp
чтобы ответить на первоначальный вопрос времени компиляции проверьте, что нет стандартизированного способа сделать это, который будет работать во всех существующих и всех будущих компиляторах, потому что ни один из существующих стандартов C, C++ и POSIX не определяет макросы для обнаружения endianness.
но, если вы хотите ограничить себя некоторым известным набором компиляторов, вы можете посмотреть каждую из этих документов компиляторов, чтобы узнать, какие предопределенные макросы (если таковые имеются) они используют для определения порядок байтов. на этой странице перечисляет несколько макросов, которые вы можете искать, поэтому вот код, который будет работать для них:
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ defined(__BIG_ENDIAN__) || \ defined(__ARMEB__) || \ defined(__THUMBEB__) || \ defined(__AARCH64EB__) || \ defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) // It's a big-endian target architecture #elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \ defined(__LITTLE_ENDIAN__) || \ defined(__ARMEL__) || \ defined(__THUMBEL__) || \ defined(__AARCH64EL__) || \ defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) // It's a little-endian target architecture #else #error "I don't know what architecture this is!" #endifесли вы не можете найти, какие предопределенные макросы использует ваш компилятор из своей документации, вы также можете попробовать заставить его выплюнуть свой полный список предопределенных макросов и угадать оттуда, что будет работать (ищите что-нибудь с именем ENDIAN, ORDER или Processor architecture в нем). на этой странице перечисляет ряд методов для ведения что в разных компиляторах:
Compiler C macros C++ macros Clang/LLVM clang -dM -E -x c /dev/null clang++ -dM -E -x c++ /dev/null GNU GCC/G++ gcc -dM -E -x c /dev/null g++ -dM -E -x c++ /dev/null Hewlett-Packard C/aC++ cc -dM -E -x c /dev/null aCC -dM -E -x c++ /dev/null IBM XL C/C++ xlc -qshowmacros -E /dev/null xlc++ -qshowmacros -E /dev/null Intel ICC/ICPC icc -dM -E -x c /dev/null icpc -dM -E -x c++ /dev/null Microsoft Visual Studio (none) (none) Oracle Solaris Studio cc -xdumpmacros -E /dev/null CC -xdumpmacros -E /dev/null Portland Group PGCC/PGCPP pgcc -dM -E (none)наконец, чтобы завершить его, компиляторы Microsoft Visual C / C++ являются нечетными и не имеют ничего из вышеперечисленного. К счастью, они задокументировали свои предопределенные макросы здесь, и вы можете использовать целевую архитектуру процессора для вывода endianness. В то время как все поддерживаемые в настоящее время процессоры в Windows являются мало-endian (
_M_IX86,_M_X64,_M_IA64и_M_ARMмало-endian), некоторые исторически поддерживаемые процессоры, такие как PowerPC (_M_PPC) были тупоконечников. Но более уместно, что Xbox 360-это машина PowerPC с большим концом, поэтому, если вы пишете кросс-платформенный заголовок библиотеки, не помешает проверить_M_PPC.
С помощью C99 вы можете выполнить проверку как:
#define I_AM_LITTLE (((union { unsigned x; unsigned char c; }){1}).c)условные конструкции типа
if (I_AM_LITTLE)будет вычисляться во время компиляции и позволить компилятору оптимизировать целые кварталы.у меня нет ссылки сразу на то, является ли это строго говоря константное выражение в C99 (что позволит использовать его в инициализаторах для данных статического хранения), но если нет, то это следующая лучшая вещь.
интересно читать от C FAQ:
Вы, наверное, не могу. Обычные методики для выявления байтов задействуйте указатели или массивы символов, или, может быть, объединения, но препроцессор арифметика использует только длинные целые числа, и нет понятия адресация. Еще одна заманчивая возможность-это что-то вроде
#if 'ABCD' == 0x41424344но это тоже ненадежно.
Не во время компиляции, но, возможно, во время выполнения. Вот функция C, которую я написал, чтобы определить endianness:
/* Returns 1 if LITTLE-ENDIAN or 0 if BIG-ENDIAN */ #include <inttypes.h> int endianness() { union { uint8_t c[4]; uint32_t i; } data; data.i = 0x12345678; return (data.c[0] == 0x78); }
С наконец, в одну линию обнаружения байтов в C препроцессор:
#include <stdint.h> #define IS_BIG_ENDIAN (*(uint16_t *)"\xff" < 0x100)любой приличный оптимизатор разрешит это во время компиляции. НКУ не менее!--1-->.
конечно
stdint.hэто C99. Для переносимости ANSI/C89 см. Doug Gwyn's Мгновенный C9x библиотека.
однажды я использовал такую конструкцию:
uint16_t HI_BYTE = 0, LO_BYTE = 1; uint16_t s = 1; if(*(uint8_t *) &s == 1) { HI_BYTE = 1; LO_BYTE = 0; } pByte[HI_BYTE] = 0x10; pByte[LO_BYTE] = 0x20;gcc с -O2 удалось сделать его полностью время компиляции. Это значит, что
HI_BYTEиLO_BYTEпеременные были полностью заменены, и даже доступ к pByte был заменен в ассемблере эквивалентом*(unit16_t *pByte) = 0x1020;.это как время компиляции, как он получает.
насколько мне известно, нет, не во время компиляции.
во время выполнения вы можете выполнить тривиальные проверки, такие как установка многобайтового значения в известную битовую строку и проверить, какие байты это приводит. Например, используя союз,
typedef union { uint32_t word; uint8_t bytes[4]; } byte_check;или литья,
uint32_t word; uint8_t * bytes = &word;обратите внимание, что для полностью переносимых проверок endianness вам необходимо учитывать как большие, так и малые системы endian и mixed-endian.
EDIT2: этот метод не работает. Представление многобайтовой константы является специфичным для компилятора / платформы и не может быть надежно использовано. Ссылка interjay дала (http://www.ideone.com/LaKpj) дает пример, где он терпит неудачу. На Solaris / SPARC тот же компилятор gcc 4.3.3 дает правильный ответ, но компилятор SUNStudio 12 будет иметь то же поведение, что и gcc 4.3.4 на x86, используемый в этой ссылке.
Итак, мы можем сделать вывод, что по-прежнему нет хорошего использования многобайтовых характер
Нашел этот новый метод, который имеет то преимущество, что он прост и время компиляции.switch('AB') { case 0x4142: printf("ASCII Big endian\n"); break; case 0x4241: printf("ASCII Little endian\n"); break; case 0xC1C2: printf("EBCDIC Big endian\n"); break; case 0xC2C1: printf("EBCDIC Little endian\n"); break; }
Редактировать:нашел даже способ сделать это в предпроцессоре:
#if 'AB' == 0x4142 #error "ASCII Big endian\n" #elif 'AB' == 0x4241 #error "ASCII Little endian\n" #elif 'AB' == 0xC1C2 #error "EBCDIC Big endian\n" #elif 'AB' == 0xC2C1 #error "EBCDIC Little endian\n" #else #error "unknown coding and endianness\n" #endifи прежде чем кто-то спросит, многобайтовые символьные константы являются ANSI-C (даже C90), но определены реализации. Вот первое полезное приложение, которое я нашел для них.
Comments