Cmacros定义来确定大端还是小端?

是否有一行macros定义来确定机器的字节顺序。 我正在使用下面的代码,但将其转换为macros将太长。

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

支持任意字节顺序的代码,可以放入一个名为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 }; 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 

你会通过检查小端系统

 O32_HOST_ORDER == O32_LITTLE_ENDIAN 

如果你有一个支持C99复合文字的编译器:

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

要么:

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

一般来说,您应该尝试编写不依赖于主机平台的字节序的代码。


独立于host-endian的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]; } 

没有标准,但包括<endian.h>在内的很多系统都会给你一些定义来寻找。

要在运行时检测字节序,您必须能够引用内存。 如果你坚持标准C语言,在内存中声明一个variables需要一个语句,但是返回一个值需要一个expression式。 我不知道如何在一个macros中做到这一点 – 这就是为什么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)) 

然后你可以使用ENDIANNESSmacros。

如果只想依靠预处理器,则必须找出预定义符号的列表。 预处理器算术没有寻址的概念。

Mac上的 GCC定义了__LITTLE_ENDIAN____BIG_ENDIAN__

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

然后,您可以添加更多的基于平台检测的预处理器条件指令,如#ifdef _WIN32

我相信这是要求的。 我只在msvc下的一个小端机上testing过。 有人在大型机器上进行确认。

  #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) { ... }代码并replaceif (true) { foo(); } if (true) { foo(); }foo(); 最糟糕的情况:编译器不做优化,你仍然得到正确的代码,但有点慢。

您实际上可以通过使用复合文字(C99)来访问临时对象的内存:

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

GCC将在编译时进行评估。

'Cnetworking库'提供处理字节序的function。 即htons(),htonl(),ntohs()和ntohl()…,其中n是“networking”(即big-endian),h是“host”(即运行码)。

这些明显的“function”(通常)被定义为macros[见<netinet / in.h>],所以使用它们没有运行开销。

下面的macros使用这些“函数”来评估字节序。

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

此外:

我唯一需要知道一个系统的字节顺序的时候,是我写出一个variables[给另一个文件],这个variables可能被另一个未知的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); 

使用内联函数而不是macros。 此外,你需要在内存中存储一​​些macros,这是一个不太好的副作用。

您可以使用静态或全局variables将其转换为短的macros,如下所示:

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

虽然没有可移植的#define或可依赖的东西,平台确实提供了标准函数来转换你的“主机”端。

一般情况下,你使用'endian'作为BIG endian,使用host endian(在x86上是LITTLE endian)进行本地计算,从而存储磁盘或networking。 你用htons()ntohs()和朋友在两者之间进行转换。

如果你正在寻找一个编译时testing,而你正在使用gcc,你可以这样做:

 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 

有关更多信息,请参阅gcc文档 。

尝试这个:

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

不要忘记,字节序不是整个故事 – char的大小可能不是8位(例如DSP),二进制补码否定不能保证(例如Cray),可能需要严格的alignment(例如SPARC,也可能是ARM 中间码未alignment)等等。

改为针对特定的CPU架构可能更好。

例如:

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

请注意,这个解决scheme也不是非常便携,因为它依赖于编译器特定的定义(没有标准,但是这里有一个很好的编译定义)。

我的答案并不像问,但是如果你的系统是小端或大端,这是非常简单的

码:

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

用于检查系统是小端还是大印度的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"); 

安静的迟到,但是…如果你绝对必须有一个macros和超便携的代码,检测并build立你的内置环境(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); } 

macros查找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; }