C Macro définition pour déterminer une grosse machine endian ou une petite machine endian?

Existe-t-il une définition de macro à une ligne pour déterminer la nature de la machine. J’utilise le code suivant mais le convertir en macro serait trop long.

unsigned char test_endian( void ) { int test_var = 1; unsigned char test_endian* = (unsigned char*)&test_var; return (test_endian[0] == NULL); } 

Code prenant en charge les ordres d’octets arbitraires, prêts à être placés dans un fichier appelé order32.h :

 #ifndef ORDER32_H #define ORDER32_H #include  #include  #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 

Vous devriez vérifier les petits systèmes endian via

 O32_HOST_ORDER == O32_LITTLE_ENDIAN 

Si vous avez un compilateur qui prend en charge les littéraux composés C99:

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

ou:

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

En général cependant, vous devriez essayer d’écrire du code qui ne dépend pas de l’endianness de la plateforme hôte.


Exemple d’implémentation indépendante de l’hôte-endianness de 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]; } 

Il n’y a pas de norme, mais sur de nombreux systèmes, y compris , vous aurez des définitions à rechercher.

Pour détecter l’endianness à l’exécution, vous devez pouvoir vous référer à la mémoire. Si vous vous en tenez à la norme C, déclarer une variable en mémoire nécessite une instruction, mais renvoyer une valeur nécessite une expression. Je ne sais pas comment faire cela en une seule macro, c’est pourquoi gcc a des extensions 🙂

Si vous souhaitez avoir un fichier .h, vous pouvez définir

 static uint32_t endianness = 0xdeadbeef; enum endianness { BIG, LITTLE }; #define ENDIANNESS ( *(const char *)&endianness == 0xef ? LITTLE \ : *(const char *)&endianness == 0xde ? BIG \ : assert(0)) 

et ensuite vous pouvez utiliser la macro ENDIANNESS comme vous le souhaitez.

Si vous ne souhaitez utiliser que le préprocesseur, vous devez déterminer la liste des symboles prédéfinis. L’arithmétique des préprocesseurs n’a pas de concept d’adressage.

GCC sur Mac définit __LITTLE_ENDIAN__ ou __BIG_ENDIAN__

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

Ensuite, vous pouvez append plus de directives conditionnelles de préprocesseur basées sur la détection de plate-forme comme #ifdef _WIN32 etc.

Je crois que c’est ce qui a été demandé. Je l’ai seulement testé sur une petite machine Endian sous msvc. Quelqu’un a confirmé sur une grosse machine endienne.

  #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 

En tant que note d’accompagnement (spécifique au compilateur), avec un compilateur agressif, vous pouvez utiliser l’optimisation “élimination du code mort” pour obtenir le même effet qu’un temps de compilation tel que:

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

Ce qui précède repose sur le fait que le compilateur reconnaît les valeurs constantes au moment de la compilation, supprime entièrement le code dans if (false) { ... } et remplace le code comme if (true) { foo(); } if (true) { foo(); } avec foo(); Le pire des scénarios: le compilateur ne fait pas l’optimisation, vous obtenez toujours un code correct mais un peu plus lent.

Si vous recherchez un test de compilation et que vous utilisez gcc, vous pouvez faire:

 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 

Voir la documentation de gcc pour plus d’informations.

Vous pouvez en effet accéder à la mémoire d’un object temporaire en utilisant un littéral composé (C99):

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

Quel GCC évaluera au moment de la compilation.

La ‘bibliothèque réseau C’ offre des fonctions pour gérer l’endian’ness. À savoir htons (), htonl (), ntohs () et ntohl () … où n est “network” (c’est-à-dire big-endian) et h est “host” (c’est-à-dire l’endian de la machine exécutant le code).

Ces «fonctions» apparentes sont (généralement) définies comme des macros [voir ], il n’y a donc pas de surcharge d’exécution pour les utiliser.

Les macros suivantes utilisent ces «fonctions» pour évaluer le caractère endian.

 #include  #define IS_BIG_ENDIAN (1 == htons(1)) #define IS_LITTLE_ENDIAN (!IS_BIG_ENDIAN) 

En outre:

La seule fois où j’ai besoin de connaître la finalité d’un système, c’est quand j’écris une variable [dans un fichier / autre] qui peut être lue par un autre système de type endian’ness inconnu (pour une compatibilité multiplate-forme) ) … Dans de tels cas, vous pouvez préférer utiliser directement les fonctions endian:

 #include  #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); 

Utilisez une fonction en ligne plutôt qu’une macro. En outre, vous devez stocker quelque chose en mémoire, ce qui est un effet secondaire peu agréable d’une macro.

Vous pouvez le convertir en une macro courte en utilisant une variable statique ou globale, comme ceci:

 static int s_endianess = 0; #define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0) 

Bien qu’il n’y ait pas de fichier portable ou de document sur lequel s’appuyer, les plates-formes fournissent des fonctions standard pour la conversion vers et depuis votre endian “hôte”.

Généralement, vous faites du stockage – sur disque ou réseau – en utilisant «endian réseau», qui est BIG endian, et le calcul local en utilisant l’hôte endian (qui sur x86 est LITTLE endian). Vous utilisez htons() et ntohs() et des amis pour convertir entre les deux.

Essaye ça:

 #include int x=1; #define TEST (*(char*)&(x)==1)?printf("little endian"):printf("Big endian") int main() { TEST; } 
 #include  #define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8) #define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8) 

N’oubliez pas que l’endianness n’est pas toute l’histoire – la taille du caractère peut ne pas être de 8 bits (par exemple, DSP), la négation du complément à deux n’est pas garantie (par exemple Cray), un alignement ssortingct peut être nécessaire. Middle-Endian lorsqu’il n’est pas aligné), etc., etc.

Il pourrait être préférable de cibler une architecture de processeur spécifique à la place.

Par exemple:

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

Notez que cette solution n’est pas non plus ultra portable, car elle dépend de définitions spécifiques au compilateur (il n’y a pas de standard, mais voici une belle compilation de ces définitions).

Ma réponse n’est pas telle que posée mais il est vraiment simple à trouver si votre système est peu endian ou big endian?

Code:

 #include int main() { int a = 1; char *b; b = (char *)&a; if (*b) printf("Little Endian\n"); else printf("Big Endian\n"); } 

C Code pour vérifier si un système est petit-endien ou grand-indien.

 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"); 

Calme tard mais … Si vous devez absolument avoir un code macro ET ultra-portable, détectez-le et configurez-le à partir de votre environnement construit (cmake / autotools).

Voici un programme simple pour le faire, convenant à la dégustation:

 #if __STDC_VERSION__ < 199901L #error "Requires C99 compatibility" #endif #include  #include  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); } 

Macro pour trouver des endiannes

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

ou

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