C语言 C 宏定义以确定大端或小端机器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2100331/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:11:51  来源:igfitidea点击:

C Macro definition to determine big endian or little endian machine?

carchitecturemacrosendianness

提问by manav m-n

Is there a one line macro definition to determine the endianness of the machine. I am using the following code but converting it to macro would be too long.

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

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

    return (test_endian[0] == 0);
}

采纳答案by Christoph

Code supporting arbitrary byte orders, ready to be put into a file called order32.h:

支持任意字节顺序的代码,准备放入名为 的文件中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

You would check for little endian systems via

您将通过以下方式检查小端系统

O32_HOST_ORDER == O32_LITTLE_ENDIAN

回答by caf

If you have a compiler that supports C99 compound literals:

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

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

or:

或者:

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

In general though, you should try to write code that does not depend on the endianness of the host platform.

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



Example of host-endianness-independent implementation of ntohl():

独立于主机字节序的实现示例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];
}

回答by Ignacio Vazquez-Abrams

There is no standard, but on many systems including <endian.h>will give you some defines to look for.

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

回答by Norman Ramsey

To detect endianness at run time, you have to be able to refer to memory. If you stick to standard C, declarating a variable in memory requires a statement, but returning a value requires an expression. I don't know how to do this in a single macro—this is why gcc has extensions :-)

要在运行时检测字节顺序,您必须能够引用内存。如果您坚持使用标准 C,那么在内存中声明一个变量需要一个语句,但返回一个值需要一个表达式。我不知道如何在单个宏中执行此操作-这就是 gcc 具有扩展的原因:-)

If you're willing to have a .h file, you can define

如果你愿意有一个 .h 文件,你可以定义

static uint32_t endianness = 0xdeadbeef; 
enum endianness { BIG, LITTLE };

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

and then you can use the ENDIANNESSmacro as you will.

然后你就可以随意使用ENDIANNESS宏了。

回答by Gregory Pakosz

If you want to only rely on the preprocessor, you have to figure out the list of predefined symbols. Preprocessor arithmetics has no concept of addressing.

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

GCC on Macdefines __LITTLE_ENDIAN__or __BIG_ENDIAN__

Mac 上的GCC定义__LITTLE_ENDIAN____BIG_ENDIAN__

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

Then, you can add more preprocessor conditional directives based on platform detection like #ifdef _WIN32etc.

然后,您可以根据平台检测#ifdef _WIN32等添加更多预处理器条件指令。

回答by ggpp23

I believe this is what was asked for. I only tested this on a little endian machine under msvc. Someone plese confirm on a big endian machine.

我相信这是被要求的。我只在 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

As a side note (compiler specific), with an aggressive compiler you can use "dead code elimination" optimization to achieve the same effect as a compile time #iflike so:

作为旁注(特定于编译器),使用激进的编译器,您可以使用“死代码消除”优化来实现与编译时相同的效果,#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; // ?
    }

The above relies on the fact that the compiler recognizes the constant values at compile time, entirely removes the code within if (false) { ... }and replaces code like if (true) { foo(); }with foo();The worst case scenario: the compiler does not do the optimization, you still get correct code but a bit slower.

以上依赖于编译器可以识别在编译时的常数值的事实,完全消除了代码中if (false) { ... }并取代这样的代码if (true) { foo(); }foo();最坏的情况:编译器不会做了优化,你仍然可以得到正确的代码,但有点慢。

回答by Jér?me Pouiller

If you are looking for a compile time test and you are using gcc, you can do:

如果您正在寻找编译时测试并且您正在使用 gcc,您可以执行以下操作:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__

See gcc documentationfor more information.

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

回答by u0b34a0f6ae

You canin fact access the memory of a temporary object by using a compound literal (C99):

实际上,您可以使用复合字面量 (C99) 访问临时对象的内存:

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

Which GCC will evaluate at compile time.

哪个 GCC 将在编译时评估。

回答by BlueChip

The 'C network library' offers functions to handle endian'ness. Namely htons(), htonl(), ntohs() and ntohl() ...where n is "network" (ie. big-endian) and h is "host" (ie. the endian'ness of the machine running the code).

“C 网络库”提供处理字节序的函数。即 htons(), htonl(), ntohs() 和 ntohl() ...其中 n 是“网络”(即大端),h 是“主机”(即运行代码)。

These apparent 'functions' are (commonly) defined as macros [see <netinet/in.h>], so there is no runtime overhead for using them.

这些明显的“函数”(通常)被定义为宏 [参见 <netinet/in.h>],因此使用它们没有运行时开销。

The following macros use these 'functions' to evaluate endian'ness.

以下宏使用这些“函数”来评估字节序。

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

In addition:

此外:

The only time I ever need to know the endian'ness of a system is when I write-out a variable [to a file/other] which may be read-in by another system of unknown endian'ness (for cross-platform compatability) ...In cases such as these, you may prefer to use the endian functions directly:

我唯一需要知道系统字节序的时候是当我写出一个变量 [到文件/其他] 时,它可能会被另一个未知字节序的系统读入(为了跨平台兼容性) ) ...在这种情况下,您可能更喜欢直接使用 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);

回答by user231967

Use an inline function rather than a macro. Besides, you need to store something in memory which is a not-so-nice side effect of a macro.

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

You could convert it to a short macro using a static or global variable, like this:

您可以使用静态或全局变量将其转换为短宏,如下所示:

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