114

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

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

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

21 回答 21

108

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

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

O32_HOST_ORDER == O32_LITTLE_ENDIAN
于 2010-01-20T16:39:01.020 回答
52

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

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

或者:

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

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


独立于主机端顺序的实现示例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];
}
于 2010-01-20T10:19:41.610 回答
45

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

于 2010-01-20T09:49:27.667 回答
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))

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

于 2010-01-20T09:52:01.487 回答
19

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

Mac 上的GCC定义__LITTLE_ENDIAN____BIG_ENDIAN__

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

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

于 2010-01-20T09:53:45.880 回答
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

作为旁注(特定于编译器),使用激进的编译器,您可以使用“死代码消除”优化来实现与编译时相同的效果,#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) { ... }并替换代码if (true) { foo(); }foo();事实最坏的情况:编译器不进行优化,你仍然得到正确的代码但有点慢。

于 2012-02-14T19:41:29.663 回答
10

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

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__

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

于 2016-11-18T10:51:22.483 回答
8

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

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

哪个 GCC 将在编译时评估。

于 2013-01-11T06:31:30.870 回答
7

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

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

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

#include <arpa/inet.h>
#define  IS_BIG_ENDIAN     (1 == htons(1))
#define  IS_LITTLE_ENDIAN  (!IS_BIG_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);
于 2013-06-12T00:27:45.623 回答
6

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

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

static int s_endianess = 0;
#define ENDIANESS() ((s_endianess = 1), (*(unsigned char*) &s_endianess) == 0)
于 2010-01-20T09:48:59.873 回答
5

虽然没有可移植的#define 或其他可依赖的东西,但平台确实提供了标准功能,用于与“主机”端进行转换。

通常,您使用“network endian”(大端)进行存储 - 到磁盘或网络,并使用主机端(在 x86 上是LITTLE端)进行本地计算。您使用htons()andntohs()和朋友在两者之间进行转换。

于 2010-01-20T09:53:40.657 回答
4
#include <stdint.h>
#define IS_LITTLE_ENDIAN (*(uint16_t*)"\0\1">>8)
#define IS_BIG_ENDIAN (*(uint16_t*)"\1\0">>8)
于 2012-02-13T17:11:39.593 回答
4

不要忘记字节序不是全部 - 大小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
}

请注意,不幸的是,此解决方案也不是超便携的,因为它取决于特定于编译器的定义(没有标准,但这里是此类定义的一个很好的编译)。

于 2016-11-02T15:44:48.410 回答
3

试试这个:

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

   TEST;
}
于 2010-01-20T09:54:13.043 回答
3

如果你转储预处理器#defines

gcc -dM -E - < /dev/null
g++ -dM -E -x c++ - < /dev/null

你通常可以找到对你有帮助的东西。带有编译时逻辑。

#define __LITTLE_ENDIAN__ 1
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__

然而,不同的编译器可能有不同的定义。

于 2019-11-14T17:07:42.263 回答
2

请注意,这里的大多数答案都是不可移植的,因为今天的编译器将在编译时评估这些答案(取决于优化)并根据特定的字节序返回一个特定的值,而实际的机器字节序可能会有所不同。测试字节序的值永远不会到达系统内存,因此无论实际字节序如何,实际执行的代码都将返回相同的结果。

例如,在 ARM Cortex-M3,实现的字节序将反映在状态位 AIRCR.ENDIANNESS 中,编译器在编译时无法知道该值。

此处建议的一些答案的编译输出:

https://godbolt.org/z/GJGNE2这个答案,

https://godbolt.org/z/Yv-pyJ这个答案,等等。

要解决它,您将需要使用volatile限定符。Yogeesh H T的答案是当今现实生活中最接近的答案,但由于提出了更全面的解决方案,因此对他的答案Christoph稍作修正将使答案完整,只需添加到联合声明中:.volatilestatic const volatile union

这将确保存储和读取内存,这是确定字节顺序所必需的。

于 2019-01-12T20:49:18.827 回答
1

这个问题对于 cpp 也是实际的,所以我在这里问。

只要#if __cplusplus > 201703L

#include <bit>
#include <iostream>

using namespace std;

int main()
{
    if constexpr (endian::native == endian::big)
        cout << "big-endian";
    else if constexpr (endian::native == endian::little)
        cout << "little-endian";
    else
        cout << "mixed-endian";
}

欲了解更多信息:https ://en.cppreference.com/w/cpp/types/endian

于 2021-12-08T02:05:00.910 回答
0

如果您的编译器支持复合文字并且您明确不使用 C++,您可以使用

#define BIG_ENDIAN      ((*(const char*)&(const int){0x01020304}) == 0x01)
#define LITTLE_ENDIAN   ((*(const char*)&(const int){0x01020304}) == 0x04)

这不需要声明任何运行时变量,我认为这比大多数其他解决方案更干净

于 2021-11-09T14:18:38.353 回答
-1

我的回答不像问的那样,但是找到你的系统是小端还是大端真的很简单?

代码:

#include<stdio.h>

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

  b = (char *)&a;
  if (*b)
    printf("Little Endian\n");
  else
    printf("Big Endian\n");
}
于 2016-04-13T15:37:59.273 回答
-1

用于检查系统是 little-endian 还是 big-indian 的 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");
于 2017-01-07T05:21:44.980 回答
-4

查找字节序的宏

#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;
}
于 2015-12-01T13:01:09.557 回答