Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在编译时确定endianness_C_Endianness - Fatal编程技术网

C 在编译时确定endianness

C 在编译时确定endianness,c,endianness,C,Endianness,是否有一种安全的、可移植的方法来确定(在编译时)我的程序所编译的平台的终结性?我在用C写 [编辑] 感谢您的回答,我决定坚持使用运行时解决方案 据我所知,不,不是在编译时 在运行时,您可以执行一些琐碎的检查,例如将多字节值设置为已知的位字符串,并检查结果是什么字节。比如使用一个联合体 typedef union { uint32_t word; uint8_t bytes[4]; } byte_check; 或铸造 uint32_t word; uint8_t * bytes

是否有一种安全的、可移植的方法来确定(在编译时)我的程序所编译的平台的终结性?我在用C写

[编辑]
感谢您的回答,我决定坚持使用运行时解决方案

据我所知,不,不是在编译时

在运行时,您可以执行一些琐碎的检查,例如将多字节值设置为已知的位字符串,并检查结果是什么字节。比如使用一个联合体

typedef union {
    uint32_t word;
    uint8_t bytes[4];
} byte_check;
或铸造

uint32_t word;
uint8_t * bytes = &word;

请注意,对于完全可移植的endian检查,您需要同时考虑big-endian、little-endian和mixed-endian系统。

这是用于编译时检查的

bool isLittleEndian()
{
    short int number = 0x1;
    char *numPtr = (char*)&number;
    return (numPtr[0] == 1);
}
您可以使用boost头文件中的信息,它涵盖了许多平台

编辑以进行运行时检查

bool isLittleEndian()
{
    short int number = 0x1;
    char *numPtr = (char*)&number;
    return (numPtr[0] == 1);
}
创建一个整数,并读取其第一个字节(最低有效字节)。如果该字节为1,则系统为小端,否则为大端

编辑并思考它


是的,您可能会在某些平台(想不出任何平台)中遇到潜在问题,其中
sizeof(char)==sizeof(short int int)
。您可以使用
中提供的固定宽度多字节整数类型,或者,如果您的平台没有固定宽度多字节整数类型,您也可以调整boost头以供使用:

不是在编译时,而是在运行时。我写了一个C函数来确定endianness:

/*  Returns 1 if LITTLE-ENDIAN or 0 if BIG-ENDIAN  */
#include <inttypes.h>
int endianness()
{
  union { uint8_t c[4]; uint32_t i; } data;
  data.i = 0x12345678;
  return (data.c[0] == 0x78);
}
/*如果是小端,则返回1;如果是大端,则返回0*/
#包括
内端性()
{
联合数据;
data.i=0x12345678;
返回(data.c[0]==0x78);
}

有趣的阅读:

你可能不能。端点检测的常用技术 涉及指针或字符数组,或者可能涉及联合,但涉及预处理器 算术只使用长整数,并且没有整数的概念 寻址。另一个诱人的可能性是

  #if 'ABCD' == 0x41424344
但这也不可靠


使用C99,您可以执行以下检查:

#define I_AM_LITTLE (((union { unsigned x; unsigned char c; }){1}).c)
if(I\u AM\u LITTLE)
这样的条件将在编译时进行计算,并允许编译器优化整个块


对于这是否严格地说是C99中的常量表达式(这将允许它在静态存储持续时间数据的初始值设定项中使用),我现在还没有参考,但如果没有,这是次好的选择。

我曾经使用过这样的构造:

uint16_t  HI_BYTE  = 0,
          LO_BYTE  = 1;
uint16_t  s = 1;

if(*(uint8_t *) &s == 1) {   
   HI_BYTE = 1;
   LO_BYTE = 0;
} 

pByte[HI_BYTE] = 0x10;
pByte[LO_BYTE] = 0x20;
带有-O2的gcc能够使它完全在编译时运行。这意味着,
HI_字节
lou字节
变量被完全替换,甚至汇编程序中的pByte访问也被替换为等价的
*(unit16_t*pByte)=0x1020


这是它得到的编译时间。

我想扩展为C提供
constepr
函数的答案++

union Mix {
    int sdat;
    char cdat[4];
};
static constexpr Mix mix { 0x1 };
constexpr bool isLittleEndian() {
    return mix.cdat[0] == 1;
}
由于
mix
也是
constexpr
,因此它是编译时,可以在
constexpr bool isLittleEndian()中使用。应该是安全的使用

使现代化 正如@chearsandhth在下面指出的,这些似乎是有问题的

原因是,它不是符合C++11标准的,这是被禁止的。每次只能有一个工会成员处于活动状态。使用符合标准的编译器,您将得到一个错误

<> >,<强>不要在C++中使用它<强>。看起来,你可以用C来做。我留下我的答案是为了教育目的:-)因为这个问题是关于C

更新2
这假设
int
的大小为4
char
s,这并不总是如下面正确指出的@PetrVepřek所示。要使代码真正可移植,您必须在这里更加聪明。不过,这在许多情况下应该足够了。请注意,根据定义,
sizeof(char)
始终是
1
。上述代码假定
sizeof(int)==4

> p>为了回答编译时检查的原始问题,没有标准化的方法来处理所有现有和将来的编译器,因为现有的C、C++和POSIX标准都没有定义用于检测迂回性的宏。 但是,如果您愿意将自己限制在一些已知的编译器集合中,您可以查找这些编译器的文档,以找出它们用于定义endianness的预定义宏(如果有的话)。列出了几个可以查找的宏,下面是一些适用于这些宏的代码:

#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
    defined(__BIG_ENDIAN__) || \
    defined(__ARMEB__) || \
    defined(__THUMBEB__) || \
    defined(__AARCH64EB__) || \
    defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
// It's a big-endian target architecture
#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
    defined(__LITTLE_ENDIAN__) || \
    defined(__ARMEL__) || \
    defined(__THUMBEL__) || \
    defined(__AARCH64EL__) || \
    defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
// It's a little-endian target architecture
#else
#error "I don't know what architecture this is!"
#endif
如果您无法从其文档中找到编译器使用的预定义宏,您也可以尝试强制它吐出其预定义宏的完整列表,并从中猜测什么将起作用(查找任何包含ENDIAN、ORDER或处理器体系结构名称的内容)。列出了在不同编译器中执行此操作的多种方法:

Compiler                   C macros                         C++ macros
Clang/LLVM                 clang -dM -E -x c /dev/null      clang++ -dM -E -x c++ /dev/null
GNU GCC/G++                gcc   -dM -E -x c /dev/null      g++     -dM -E -x c++ /dev/null
Hewlett-Packard C/aC++     cc    -dM -E -x c /dev/null      aCC     -dM -E -x c++ /dev/null
IBM XL C/C++               xlc   -qshowmacros -E /dev/null  xlc++   -qshowmacros -E /dev/null
Intel ICC/ICPC             icc   -dM -E -x c /dev/null      icpc    -dM -E -x c++ /dev/null
Microsoft Visual Studio (none)                              (none)
Oracle Solaris Studio      cc    -xdumpmacros -E /dev/null  CC      -xdumpmacros -E /dev/null
Portland Group PGCC/PGCPP  pgcc  -dM -E                     (none)
最后,为了圆满解决这个问题,MicrosoftVisualC/C++编译器是一些奇怪的编译器,没有上面提到的任何一个。幸运的是,他们已经记录了预定义的宏,您可以使用目标处理器体系结构来推断endianness。虽然Windows中当前支持的所有处理器都是little endian(
\u M_IX86
\u M_X64
\u M_IA64
)和
\u ARM
都是little endian),但一些历史上支持的处理器,如PowerPC(
\u PPC
)都是big endian。但更相关的是,Xbox 360是一台高端PowerPC机器,因此如果您正在编写一个跨平台库头,那么从以下位置检查
\u M_PPC

#包括
#定义为大尾端(*(uint16\u t*)“\0\xff”<0x100)
任何合适的优化器都会在编译时解决这个问题。gcc不在
-O1

当然,
stdint.h
是C99。有关ANSI/C89的可移植性,请参见Doug Gwyn的库。

使用CMake作为


就我而言,我决定使用一种中间方法:尝试宏,如果它们不存在,或者我们不能
INCLUDE(TestBigEndian)
TEST_BIG_ENDIAN(ENDIAN)
IF (ENDIAN)
    # big endian
ELSE (ENDIAN)
    # little endian
ENDIF (ENDIAN)
#define II      0x4949     // arbitrary values != 1; examples are
#define MM      0x4D4D     // taken from the TIFF standard

int
#if defined __BYTE_ORDER__ && __BYTE_ORDER__ == __LITTLE_ENDIAN
     const host_endian = II;
# elif defined __BYTE_ORDER__ && __BYTE_ORDER__ == __BIG__ENDIAN
     const host_endian = MM;
#else
#define _no_BYTE_ORDER
     host_endian = 1;            // plain "int", not "int const" !
#endif
int main(int argc, char **argv) {
#ifdef _no_BYTE_ORDER
    host_endian = * (char *) &host_endian ? II : MM;
#undef _no_BYTE_ORDER
#endif

// .... your code here, for instance:
printf("Endedness: %s\n", host_endian == II ? "little-endian"
                                            : "big-endian");

return 0;
}
#define BYTEORDER_LITTLE_ENDIAN 0 // Little endian machine.
#define BYTEORDER_BIG_ENDIAN 1 // Big endian machine.

//#define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN

#ifndef BYTEORDER_ENDIAN
    // Detect with GCC 4.6's macro.
#   if defined(__BYTE_ORDER__)
#       if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#           define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#       elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#           define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN
#       else
#           error "Unknown machine byteorder endianness detected. User needs to define BYTEORDER_ENDIAN."
#       endif
    // Detect with GLIBC's endian.h.
#   elif defined(__GLIBC__)
#       include <endian.h>
#       if (__BYTE_ORDER == __LITTLE_ENDIAN)
#           define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#       elif (__BYTE_ORDER == __BIG_ENDIAN)
#           define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN
#       else
#           error "Unknown machine byteorder endianness detected. User needs to define BYTEORDER_ENDIAN."
#       endif
    // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro.
#   elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
#       define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#   elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
#       define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN
    // Detect with architecture macros.
#   elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
#       define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN
#   elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
#       define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#   elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
#       define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN
#   else
#       error "Unknown machine byteorder endianness detected. User needs to define BYTEORDER_ENDIAN."
#   endif
#endif