C Определение макроса для определения большой конечной или малоконечной машины?
Существует ли определение макроса в одной строке для определения конечности машины. Я использую следующий код, но преобразование его в макрос будет слишком длинным.
unsigned char test_endian( void )
{
int test_var = 1;
unsigned char test_endian* = (unsigned char*)&test_var;
return (test_endian[0] == NULL);
}
Ответы
Ответ 1
Код, поддерживающий произвольные байтовые заказы, готовые к вводу в файл с именем order32.h
:
#ifndef ORDER32_H
#define ORDER32_H
#include <limits.h>
#include <stdint.h>
#if CHAR_BIT != 8
#error "unsupported char size"
#endif
enum
{
O32_LITTLE_ENDIAN = 0x03020100ul,
O32_BIG_ENDIAN = 0x00010203ul,
O32_PDP_ENDIAN = 0x01000302ul, /* DEC PDP-11 (aka ENDIAN_LITTLE_WORD) */
O32_HONEYWELL_ENDIAN = 0x02030001ul /* Honeywell 316 (aka ENDIAN_BIG_WORD) */
};
static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order =
{ { 0, 1, 2, 3 } };
#define O32_HOST_ORDER (o32_host_order.value)
#endif
Вы проверите для маленьких систем endian через
O32_HOST_ORDER == O32_LITTLE_ENDIAN
Ответ 2
Если у вас есть компилятор, который поддерживает сложные литералы C99:
#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})
или
#define IS_BIG_ENDIAN (!(union { uint16_t u16; unsigned char c; }){ .u16 = 1 }.c)
В целом, однако, вы должны попытаться написать код, который не зависит от конечности хост-платформы.
Пример независимой от хоста реализации ntohl()
:
uint32_t ntohl(uint32_t n)
{
unsigned char *np = (unsigned char *)&n;
return ((uint32_t)np[0] << 24) |
((uint32_t)np[1] << 16) |
((uint32_t)np[2] << 8) |
(uint32_t)np[3];
}
Ответ 3
Нет стандарта, но на многих системах, включая <endian.h>
, вы получите некоторые определения для поиска.
Ответ 4
Чтобы определить достоверность во время выполнения, вы должны иметь возможность обращаться к памяти. Если вы придерживаетесь стандарта C, для объявления переменной в памяти требуется инструкция, но для возврата значения требуется выражение. Я не знаю, как это сделать в одном макросе, поэтому gcc имеет расширения: -)
Если вы хотите иметь файл .h, вы можете определить
static uint32_t endianness = 0xdeadbeef;
enum endianness { BIG, LITTLE };
#define ENDIANNESS ( *(const char *)&endianness == 0xef ? LITTLE \
: *(const char *)&endianness == 0xde ? BIG \
: assert(0))
а затем вы можете использовать макрос ENDIANNESS
, как вы.
Ответ 5
Если вы хотите полагаться только на препроцессор, вам нужно выяснить список предопределенных символов. Арифметика препроцессора не имеет понятия адресации.
GCC на Mac определяет __LITTLE_ENDIAN__
или __BIG_ENDIAN__
$ gcc -E -dM - < /dev/null |grep ENDIAN
#define __LITTLE_ENDIAN__ 1
Затем вы можете добавить дополнительные условные директивы препроцессора на основе определения платформы, например #ifdef _WIN32
и т.д.
Ответ 6
Я считаю, что это то, о чем просили.
Я тестировал это только на маленькой конечной машине в msvc.
Кто-то говорит на большой машине.
#define LITTLE_ENDIAN 0x41424344UL
#define BIG_ENDIAN 0x44434241UL
#define PDP_ENDIAN 0x42414443UL
#define ENDIAN_ORDER ('ABCD')
#if ENDIAN_ORDER==LITTLE_ENDIAN
#error "machine is little endian"
#elif ENDIAN_ORDER==BIG_ENDIAN
#error "machine is big endian"
#elif ENDIAN_ORDER==PDP_ENDIAN
#error "jeez, machine is PDP!"
#else
#error "What kind of hardware is this?!"
#endif
Как побочная заметка (специфическая для компилятора), с агрессивным компилятором вы можете использовать оптимизацию "устранения мертвого кода" для достижения того же эффекта, что и время компиляции #if
:
unsigned yourOwnEndianSpecific_htonl(unsigned n)
{
static unsigned long signature= 0x01020304UL;
if (1 == (unsigned char&)signature) // big endian
return n;
if (2 == (unsigned char&)signature) // the PDP style
{
n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
return n;
}
if (4 == (unsigned char&)signature) // little endian
{
n = (n << 16) | (n >> 16);
n = ((n << 8) & 0xFF00FF00UL) | ((n>>8) & 0x00FF00FFUL);
return n;
}
// only weird machines get here
return n; // ?
}
Вышеизложенное полагается на то, что компилятор распознает постоянные значения во время компиляции, полностью удаляет код внутри if (false) { ... }
и заменяет код, например if (true) { foo(); }
на foo();
Худший сценарий: компилятор не выполняет оптимизация, вы все равно получаете правильный код, но немного медленнее.
Ответ 7
Если вы ищете тест времени компиляции и используете gcc, вы можете:
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Дополнительную информацию см. В документации по gcc.
Ответ 8
Фактически вы можете получить доступ к памяти временного объекта, используя составной литерал (C99):
#define IS_LITTLE_ENDIAN (1 == *(unsigned char *)&(const int){1})
Какой GCC будет оцениваться во время компиляции.
Ответ 9
"Сетевая библиотека C" предлагает функции для обработки endian'ness. А именно htons(), htonl(), ntohs() и ntohl()... где n - "сеть" (т.е. Big-endian), а h - "host" (т.е. Конечность машины, код).
Эти очевидные "функции" (обычно) определяются как макросы [см. < netinet/in.h > ], поэтому для их использования нет служебных данных времени выполнения.
Следующие макросы используют эти "функции" для оценки сущности.
#include <arpa/inet.h>
#define IS_BIG_ENDIAN (1 == htons(1))
#define IS_LITTLE_ENDIAN (!IS_BIG_ENDIAN)
Кроме того:
Единственный раз, когда мне когда-либо нужно знать конечность системы, - это когда я выписываю переменную [в файл/другую], которая может быть прочитана другой системой неизвестной цели (для креста -платформенная совместимость)... В таких случаях вы можете напрямую использовать функции endian:
#include <arpa/inet.h>
#define JPEG_MAGIC (('J'<<24) | ('F'<<16) | ('I'<<8) | 'F')
// Result will be in 'host' byte-order
unsigned long jpeg_magic = JPEG_MAGIC;
// Result will be in 'network' byte-order (IE. Big-Endian/Human-Readable)
unsigned long jpeg_magic = htonl(JPEG_MAGIC);
Ответ 10
Используйте встроенную функцию, а не макрос. Кроме того, вам нужно сохранить что-то в памяти, что является не очень приятным побочным эффектом макроса.
Вы можете преобразовать его в короткий макрос, используя статическую или глобальную переменную, например:
static int s_endianess = 0;
#define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0)
Ответ 11
В то время как нет переносного #define или чего-то, на что можно положиться, платформы предоставляют стандартные функции для преобразования в и из вашего конечного пользователя.
Как правило, вы делаете память - на диск или в сети - используя "сетевой endian", который является BIG endian, и локальное вычисление с использованием endin конечного пользователя (который на x86 является LITTLE endian). Вы используете htons()
и ntohs()
и друзей для преобразования между ними.
Ответ 12
Попробуйте следующее:
#include<stdio.h>
int x=1;
#define TEST (*(char*)&(x)==1)?printf("little endian"):printf("Big endian")
int main()
{
TEST;
}
Ответ 13
#include <stdint.h>
#define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8)
#define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8)
Ответ 14
Не забывайте, что континент - это не вся история - размер char
может не быть 8 битами (например, DSP), отрицание двух дополнений не гарантируется (например, Cray), может потребоваться строгое выравнивание (например, SPARC, также ARM пружин переходит на средний конец, когда не выравнивается) и т.д. и т.д.
Возможно, лучше ориентировать конкретную архитектуру процессора.
Например:
#if defined(__i386__) || defined(_M_IX86) || defined(_M_IX64)
#define USE_LITTLE_ENDIAN_IMPL
#endif
void my_func()
{
#ifdef USE_LITTLE_ENDIAN_IMPL
// Intel x86-optimized, LE implementation
#else
// slow but safe implementation
#endif
}
Обратите внимание, что это решение также не является ультрапортативным, поскольку оно зависит от определений, специфичных для компилятора (нет стандарта, но здесь хорошая компиляция таких определений).
Ответ 15
Мой ответ не так задан, но действительно ли можно найти , если ваша система имеет немного endian или big endian?
Код:
#include<stdio.h>
int main()
{
int a = 1;
char *b;
b = (char *)&a;
if (*b)
printf("Little Endian\n");
else
printf("Big Endian\n");
}
Ответ 16
C Код для проверки, является ли система малозначительной или большой-индийской.
int i = 7;
char* pc = (char*)(&i);
if (pc[0] == '\x7') // aliasing through char is ok
puts("This system is little-endian");
else
puts("This system is big-endian");
Ответ 17
Пожалуйста, обратите внимание, что большинство ответов здесь не являются переносимыми, поскольку современные компиляторы будут оценивать эти ответы во время компиляции (зависит от оптимизации) и возвращать конкретное значение на основе определенного порядкового номера, тогда как фактический порядковый номер машины может отличаться. Значения, на которых проверяется порядок байтов, никогда не достигнут системной памяти, поэтому реальный исполняемый код будет возвращать один и тот же результат независимо от фактического порядка байтов.
Например, в ARM Cortex-M3 реализованная последовательность будет отражаться в бите состояния AIRCR.ENDIANNESS, и компилятор не может знать это значение во время компиляции.
Вывод компиляции для некоторых ответов, предложенных здесь:
https://godbolt.org/z/GJGNE2 для этого ответа,
https://godbolt.org/z/Yv-pyJ для этого ответа и так далее.
Чтобы решить ее, вам нужно будет использовать volatile
квалификатор. Yogeesh HT
является наиболее близким к сегодняшнему использованию в реальной жизни, но поскольку Christoph
предлагает более комплексное решение, небольшое исправление его ответа сделает ответ полным, просто добавьте volatile
к объявлению union: static const volatile union
.
Это обеспечит сохранение и чтение из памяти, что необходимо для определения порядка байтов.
Ответ 18
Тихо поздно, но... Если вы абсолютно должны иметь макро и ультрапортативный код, обнаружите и установите его из встроенной среды (cmake/autotools).
Вот простая программа, чтобы просто сделать это, подходящую для grepping:
#if __STDC_VERSION__ < 199901L
#error "Requires C99 compatibility"
#endif
#include <stdint.h>
#include <stdio.h>
const char MAGIC[4] = {0xDE, 0xAD, 0xBE, 0xEF};
int
main(void) {
uint32_t magical = *(const uint32_t *)MAGIC;
switch(magical) {
case 0xEFBEADDE: printf("little\n"); break;
case 0xDEADBEEF: printf("big\n"); break;
case 0xADDEEFBE: printf("pdp\n"); break;
default: for(; magical; magical >>= 8) {
switch(magical & 0xff) {
case 0xDE: printf("3"); break;
case 0xAD: printf("2"); break;
case 0xBE: printf("1"); break;
default: printf("0"); }
} printf("\n");}
return (0);
}
Ответ 19
Макро, чтобы найти endiannes
#define ENDIANNES() ((1 && 1 == 0) ? printf("Big-Endian"):printf("Little-Endian"))
или
#include <stdio.h>
#define ENDIAN() { \
volatile unsigned long ul = 1;\
volatile unsigned char *p;\
p = (volatile unsigned char *)&ul;\
if (*p == 1)\
puts("Little endian.");\
else if (*(p+(sizeof(unsigned long)-1)) == 1)\
puts("Big endian.");\
else puts("Unknown endian.");\
}
int main(void)
{
ENDIAN();
return 0;
}