man*_*m-n 101 c architecture macros endianness
是否有一行宏定义来确定机器的字节顺序.我使用以下代码,但将其转换为宏将太长.
unsigned char test_endian( void )
{
int test_var = 1;
unsigned char test_endian* = (unsigned char*)&test_var;
return (test_endian[0] == NULL);
}
Run Code Online (Sandbox Code Playgroud)
Chr*_*oph 94
支持任意字节顺序的代码,准备放入一个名为的文件中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
Run Code Online (Sandbox Code Playgroud)
您将检查通过的小端系统
O32_HOST_ORDER == O32_LITTLE_ENDIAN
Run Code Online (Sandbox Code Playgroud)
caf*_*caf 44
如果您有一个支持C99复合文字的编译器:
#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})
Run Code Online (Sandbox Code Playgroud)
要么:
#define IS_BIG_ENDIAN (!(union { uint16_t u16; unsigned char c; }){ .u16 = 1 }.c)
Run Code Online (Sandbox Code Playgroud)
通常,您应该尝试编写不依赖于主机平台的字节顺序的代码.
与host-endianness无关的实现示例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];
}
Run Code Online (Sandbox Code Playgroud)
Ign*_*ams 39
没有标准,但在许多系统上,包括<endian.h>将给你一些定义来寻找.
Nor*_*sey 27
要在运行时检测字节序,您必须能够引用内存.如果坚持使用标准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))
Run Code Online (Sandbox Code Playgroud)
然后你可以随意使用ENDIANNESS宏.
Gre*_*osz 19
如果您只想依赖预处理器,则必须找出预定义符号列表.预处理器算术没有寻址的概念.
Mac上的 GCC 定义__LITTLE_ENDIAN__或__BIG_ENDIAN__
$ gcc -E -dM - < /dev/null |grep ENDIAN
#define __LITTLE_ENDIAN__ 1
Run Code Online (Sandbox Code Playgroud)
然后,您可以添加更多基于平台检测#ifdef _WIN32等的预处理器条件指令.
小智 15
我相信这就是要求的.我只在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
Run Code Online (Sandbox Code Playgroud)
作为附注(特定于编译器),使用积极的编译器,您可以使用"死代码消除"优化来实现与编译时相同的效果,#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; // ?
}
Run Code Online (Sandbox Code Playgroud)
以上依赖于编译器可以识别在编译时的常数值的事实,完全去除内的代码if (false) { ... },并替换如代码if (true) { foo(); }与foo();最坏的情况:编译器不会做了优化,你仍然可以得到正确的代码,但有点慢.
如果您正在寻找编译时测试并且您正在使用gcc,则可以执行以下操作:
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请参阅gcc文档.
实际上,您可以使用复合文字(C99)访问临时对象的内存:
#define IS_LITTLE_ENDIAN (1 == *(unsigned char *)&(const int){1})
Run Code Online (Sandbox Code Playgroud)
哪个GCC将在编译时进行评估.
如果你转储预处理器#defines
gcc -dM -E - < /dev/null
g++ -dM -E -x c++ - < /dev/null
Run Code Online (Sandbox Code Playgroud)
您通常可以找到对您有帮助的东西。具有编译时逻辑。
#define __LITTLE_ENDIAN__ 1
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
Run Code Online (Sandbox Code Playgroud)
然而,不同的编译器可能有不同的定义。
"C网络库"提供了处理字节序的功能.即htons(),htonl(),ntohs()和ntohl()...其中n是"network"(即big-endian),h是"host"(即运行the的机器的endian')码).
这些明显的"函数"(通常)定义为宏[请参阅<netinet/in.h>],因此使用它们没有运行时开销.
以下宏使用这些"函数"来评估字节序.
#include <arpa/inet.h>
#define IS_BIG_ENDIAN (1 == htons(1))
#define IS_LITTLE_ENDIAN (!IS_BIG_ENDIAN)
Run Code Online (Sandbox Code Playgroud)
此外:
我唯一需要知道系统的字节序的时候就是我写出一个变量[到一个文件/其他],这个变量可能被另一个未知字节序系统读入(用于跨平台兼容性) )...在这些情况下,您可能更喜欢直接使用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);
Run Code Online (Sandbox Code Playgroud)
小智 6
使用内联函数而不是宏.此外,你需要在内存中存储一些宏,这是一个不太好的副作用.
您可以使用静态或全局变量将其转换为短宏,如下所示:
static int s_endianess = 0;
#define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0)
Run Code Online (Sandbox Code Playgroud)
虽然没有可移植的#define或依赖的东西,但平台确实提供了与"主机"端口进行转换的标准功能.
通常,您使用'network endian'(BIG端)进行存储 - 磁盘或网络存储,使用主机端进行本地计算(在x86上为LITTLE端).你使用htons()和ntohs()朋友在两者之间进行转换.
不要忘记字节序并不是全部 - 大小char可能不是 8 位(例如 DSP),不保证二进制补码否定(例如 Cray),可能需要严格对齐(例如 SPARC,ARM 也进入中间) -endian未对齐时),等等。
相反,针对特定的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
}
Run Code Online (Sandbox Code Playgroud)
请注意,不幸的是,该解决方案也不是超级可移植的,因为它取决于特定于编译器的定义(没有标准,但这里是此类定义的一个很好的编译)。