C makro definicja określić big endian lub little endian maszyny?

Czy istnieje jednoliniowa Definicja makra do określenia endianness maszyny. Używam poniższego kodu, ale konwersja go do makra byłaby zbyt długa.

unsigned char test_endian( void )
{
    int test_var = 1;
    unsigned char test_endian* = (unsigned char*)&test_var;

    return (test_endian[0] == NULL);
}
Author: Ryan Haining, 2010-01-20

18 answers

Kod obsługujący dowolne rozkazy bajtów, gotowy do umieszczenia w pliku o nazwie 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

Możesz sprawdzić systemy little endian poprzez

O32_HOST_ORDER == O32_LITTLE_ENDIAN
 88
Author: Christoph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-29 22:02:30

Jeśli masz kompilator, który obsługuje litery złożone C99:

#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})

Lub:

#define IS_BIG_ENDIAN (!(union { uint16_t u16; unsigned char c; }){ .u16 = 1 }.c)

Ogólnie rzecz biorąc, powinieneś spróbować napisać kod, który nie zależy od endianness platformy hosta.


Przykład niezależnej od hosta implementacji 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];
}
 39
Author: caf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-16 04:09:54

Nie ma standardu, ale na wielu systemach, w tym <endian.h> da ci kilka definicji do szukania.

 33
Author: Ignacio Vazquez-Abrams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-20 09:49:27

Aby wykryć endianess w czasie wykonywania, musisz być w stanie odwołać się do pamięci. Jeśli trzymasz się standardu C, deklaracja zmiennej w pamięci wymaga instrukcji, ale zwrócenie wartości wymaga wyrażenia. Nie wiem jak to zrobić w jednym makrze-dlatego gcc ma rozszerzenia: -)

Jeśli chcesz mieć .plik h, można zdefiniować
static uint32_t endianness = 0xdeadbeef; 
enum endianness { BIG, LITTLE };

#define ENDIANNESS ( *(const char *)&endianness == 0xef ? LITTLE \
                   : *(const char *)&endianness == 0xde ? BIG \
                   : assert(0))

A następnie możesz użyć makra ENDIANNESS tak, jak chcesz.

 25
Author: Norman Ramsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-20 09:52:01

Jeśli chcesz polegać tylko na preprocesorze, musisz poznać listę predefiniowanych symboli. Arytmetyka preprocesora nie ma pojęcia o adresowaniu.

GCC na Mac Definiuje __LITTLE_ENDIAN__ lub __BIG_ENDIAN__

$ gcc -E -dM - < /dev/null |grep ENDIAN
#define __LITTLE_ENDIAN__ 1

Następnie możesz dodać więcej preprocesorowych dyrektyw warunkowych opartych na wykrywaniu platformy, takich jak #ifdef _WIN32 itd.

 19
Author: Gregory Pakosz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-08 02:18:36

Myślę, że o to właśnie proszono. Testowałem to tylko na małej maszynie endian pod msvc. Ktoś plese potwierdzi na wielkiej endiańskiej maszynie.

    #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

Jako dodatkowa uwaga (specyficzna dla kompilatora), z agresywnym kompilatorem możesz użyć optymalizacji "dead code elimination", aby osiągnąć taki sam efekt jak czas kompilacji #if Jak Tak:

    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; // ?
    }

Powyższe polega na tym, że kompilator rozpoznaje wartości stałe w czasie kompilacji, całkowicie usuwa kod w obrębie if (false) { ... } i zastępuje kod if (true) { foo(); } foo(); w najgorszym przypadku: kompilator nie wykonuje optymalizacji, nadal otrzymujesz poprawny kod, ale nieco wolniejszy.

 13
Author: ggpp23,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-14 19:41:29

Jeśli szukasz testu czasu kompilacji i używasz gcc, możesz to zrobić:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__

Zobacz Dokumentacja gcc aby uzyskać więcej informacji.

 8
Author: Jezz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-18 10:51:22

Możesz w rzeczywistości uzyskać dostęp do pamięci obiektu tymczasowego za pomocą literału złożonego (C99):

#define IS_LITTLE_ENDIAN (1 == *(unsigned char *)&(const int){1})

Które GCC oceni podczas kompilacji.

 7
Author: u0b34a0f6ae,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-11 06:31:30

'biblioteka sieciowa C' oferuje funkcje do obsługi endian ' Ness. Mianowicie htons (), htonl (), ntohs () i ntohl ()...gdzie n to "sieć" (tj. big-endian), A h to "gospodarz" (tj. endyjskość maszyny uruchamiającej kod).

Te pozorne 'funkcje' są (powszechnie) definiowane jako makra [patrz ], więc nie ma narzutu do ich używania.

Następujące makra używają tych 'funkcji' do oceny endianowości.

#include <arpa/inet.h>
#define  IS_BIG_ENDIAN     (1 == htons(1))
#define  IS_LITTLE_ENDIAN  (!IS_BIG_ENDIAN)

DODATKOWO:

The only czas, w którym muszę znać endianskość systemu, to kiedy wypisuję zmienną [do pliku/innego], która może być wczytana przez inny system o nieznanej endianskości (dla kompatybilności między platformami) ... w takich przypadkach, możesz woleć używać funkcji endian bezpośrednio:

#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);
 7
Author: BlueChip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-13 06:36:52

Użyj funkcji inline zamiast makra. Poza tym musisz zapisać coś w pamięci, co jest niezbyt miłym efektem ubocznym makra.

Możesz przekonwertować je na krótkie makro używając zmiennej statycznej lub globalnej, jak to:

static int s_endianess = 0;
#define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0)
 5
Author: user231967,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-20 09:48:59

Chociaż nie ma przenośnego #define lub czegoś, na czym można polegać, platformy zapewniają standardowe funkcje do konwersji do i z twojego "hosta" endian.

Ogólnie rzecz biorąc, wykonujesz przechowywanie na dysku lub sieć używając 'network endian' , który jest BIG endian, i lokalne obliczenia używając hosta endian (który na x86 jest LITTLE endian). Używasz htons() i ntohs() i przyjaciół do konwersji między nimi.

 5
Author: Will,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-20 09:53:40

Spróbuj tego:

#include<stdio.h>        
int x=1;
#define TEST (*(char*)&(x)==1)?printf("little endian"):printf("Big endian")
int main()
{

   TEST;
}
 3
Author: Prasoon Saurav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-20 09:54:13
#include <stdint.h>
#define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8)
#define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8)
 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-13 17:11:39

Nie zapominaj, że endianess to nie cała historia - Rozmiar char może nie być 8 bitów (np. DSP), negacja dopełniacza dwóch nie jest gwarantowana( np. Cray), może być wymagane ścisłe wyrównanie (np. SPARC, także ARM sprężyny do middle-endian gdy nie jest wyrównany), itd., itp.

Lepszym pomysłem może być kierowanie na konkretną architekturę procesora .

Na przykład:

#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
}

Zauważ, że to rozwiązanie również nie jest ultra-przenośne niestety, ponieważ zależy od definicji specyficznych dla kompilatora(nie ma standardu, ale Oto Ładna kompilacja takich definicji).

 3
Author: rustyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-05 17:58:13

Moja odpowiedź nie jest taka, jak pytano, ale naprawdę łatwo jest znaleźć Jeśli Twój system to little endian lub big endian?

Kod:

#include<stdio.h>

int main()
{
  int a = 1;
  char *b;

  b = (char *)&a;
  if (*b)
    printf("Little Endian\n");
  else
    printf("Big Endian\n");
}
 0
Author: roottraveller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-13 15:37:59

Kod C do sprawdzania, czy system jest little-endian czy big-indian.

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");
 0
Author: S. M. AMRAN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-07 05:21:44

Cicho późno, ale... Jeśli absolutnie musisz mieć kod makro i ultra-przenośny, Wykryj i ustaw go z wbudowanego środowiska (cmake / autotools).

Oto prosty program, który wystarczy zrobić, odpowiedni do greppingu:

#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);
}
 -1
Author: Barry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-03 21:23:34

Makro do znalezienia endiannes

#define ENDIANNES() ((1 && 1 == 0) ? printf("Big-Endian"):printf("Little-Endian"))

Lub

#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;
}
 -2
Author: Yogeesh H T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-02 06:35:29