C语言 在编译时确定字节序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4239993/
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
Determining endianness at compile time
提问by
Is there a safe, portable way to determine (during compile time) the endianness of the platform that my program is being compiled on? I'm writing in C.
是否有一种安全、可移植的方法来确定(在编译期间)我的程序正在编译的平台的字节序?我用C写。
[EDIT] Thanks for the answers, I decided to stick with the runtime solution!
[编辑] 感谢您的回答,我决定坚持使用运行时解决方案!
采纳答案by wkl
This is for compile time checking
这是用于编译时检查
You could use information from the boost header file endian.hpp, which covers many platforms.
您可以使用endian.hpp包含许多平台的 boost 头文件中的信息。
edit for runtime checking
编辑运行时检查
bool isLittleEndian()
{
short int number = 0x1;
char *numPtr = (char*)&number;
return (numPtr[0] == 1);
}
Create an integer, and read its first byte (least significant byte). If that byte is 1, then the system is little endian, otherwise it's big endian.
创建一个整数,并读取它的第一个字节(最低有效字节)。如果该字节为 1,则系统为小端,否则为大端。
edit Thinking about it
编辑考虑一下
Yes you could run into a potential issue in some platforms (can't think of any) where sizeof(char) == sizeof(short int). You could use fixed width multi-byte integral types available in <stdint.h>, or if your platform doesn't have it, again you could adapt a boost header for your use: stdint.hpp
是的,您可能会在某些平台(想不出任何)中遇到潜在问题,其中sizeof(char) == sizeof(short int). 你可以使用固定宽度多字节整数类型提供<stdint.h>,或者如果你的平台没有它,你又能够适应您使用升压头:stdint.hpp
回答by Adam Rosenfield
To answer the original question of a compile-timecheck, there's no standardized way to do it that will work across all existing and all future compilers, because none of the existing C, C++, and POSIX standards define macros for detecting endianness.
为了回答编译时检查的原始问题,没有一种标准化的方法可以在所有现有和所有未来编译器中工作,因为现有的 C、C++ 和 POSIX 标准都没有定义用于检测字节序的宏。
But, if you're willing to limit yourself to some known set of compilers, you can look up each of those compilers' documentations to find out which predefined macros (if any) they use to define endianness. This pagelists several macros you can look for, so here's some code which would work for those:
但是,如果您愿意将自己限制在一些已知的编译器集上,您可以查找每个编译器的文档以找出它们用于定义字节序的预定义宏(如果有的话)。 此页面列出了您可以查找的几个宏,因此这里有一些适用于这些宏的代码:
#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
If you can't find what predefined macros your compiler uses from its documentation, you can also try coercing it to spit out its full list of predefined macros and guess from there what will work (look for anything with ENDIAN, ORDER, or the processor architecture name in it). This pagelists a number of methods for doing that in different compilers:
如果你无法从它的文档中找到你的编译器使用的预定义宏,你也可以尝试强制它输出预定义宏的完整列表,然后从那里猜测什么会起作用(寻找任何带有 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)
Finally, to round it out, the Microsoft Visual C/C++ compilers are the odd ones out and don't have any of the above. Fortunately, they have documented their predefined macros here, and you can use the target processor architecture to infer the endianness. While all of the currently supported processors in Windows are little-endian (_M_IX86, _M_X64, _M_IA64, and _M_ARMare little-endian), some historically supported processors like the PowerPC (_M_PPC) were big-endian. But more relevantly, the Xbox 360 is a big-endian PowerPC machine, so if you're writing a cross-platform library header, it can't hurt to check for _M_PPC.
最后,要完善一下,Microsoft Visual C/C++ 编译器是奇怪的编译器,没有上述任何一个。幸运的是,他们在此处记录了他们的预定义宏,您可以使用目标处理器架构来推断字节序。尽管 Windows 中当前支持的所有处理器都是小端(_M_IX86、_M_X64、_M_IA64和_M_ARM是小端),但一些历史上支持的处理器,如 PowerPC ( _M_PPC) 是大端。但更相关的是,Xbox 360 是大端 PowerPC 机器,因此如果您正在编写跨平台库头文件,检查_M_PPC.
回答by R.. GitHub STOP HELPING ICE
With C99, you can perform the check as:
使用 C99,您可以执行以下检查:
#define I_AM_LITTLE (((union { unsigned x; unsigned char c; }){1}).c)
Conditionals like if (I_AM_LITTLE)will be evaluated at compile-time and allow the compiler to optimize out whole blocks.
条件 likeif (I_AM_LITTLE)将在编译时进行评估,并允许编译器优化整个块。
I don't have the reference right off for whether this is strictly speaking a constant expressionin C99 (which would allow it to be used in initializers for static-storage-duration data), but if not, it's the next best thing.
我没有关于这是否严格来说是C99 中的常量表达式的参考(这将允许它在静态存储持续时间数据的初始化程序中使用),但如果不是,它是下一个最好的事情。
回答by Daniel B?lu??
Interesting read from the C FAQ:
有趣的阅读 C 常见问题解答:
You probably can't. The usual techniques for detecting endianness involve pointers or arrays of char, or maybe unions, but preprocessor arithmetic uses only long integers, and there is no concept of addressing. Another tempting possibility is something like
#if 'ABCD' == 0x41424344but this isn't reliable, either.
你可能不能。检测字节序的常用技术涉及指针或字符数组,或者联合,但预处理器算术仅使用长整数,并且没有寻址的概念。另一种诱人的可能性是类似
#if 'ABCD' == 0x41424344但这也不可靠。
回答by towi
I would like to extend the answers for providing a constexprfunction for C++
我想扩展constexpr为 C++提供函数的答案
union Mix {
int sdat;
char cdat[4];
};
static constexpr Mix mix { 0x1 };
constexpr bool isLittleEndian() {
return mix.cdat[0] == 1;
}
Since mixis constexprtoo it is compile time and can be used in constexpr bool isLittleEndian(). Should be safe to use.
由于mix也是constexpr编译时,因此可以在constexpr bool isLittleEndian(). 应该可以安全使用。
Update
更新
As @Cheersandhth pointed out below, these seems to be problematic.
正如@Cheersandhth 在下面指出的那样,这些似乎有问题。
The reason is, that it is not C++11-Standard conform, where type punningis forbidden. There can always only one union member be activeat a time. With a standard conforming compiler you will get an error.
原因是,它不是 C++11-Standard 标准,禁止类型双关。一次只能有一个工会成员处于活动状态。使用符合标准的编译器,您将收到错误消息。
So, don't use itin C++. It seems, you can do it in C though. I leave my answer in for educational purposes :-) and because the question is about C...
所以,不要在 C++ 中使用它。看来,你可以用 C 来做。我出于教育目的留下我的答案:-) 并且因为问题是关于 C ...
Update 2
更新 2
This assumes that inthas the size of 4 chars, which is not always given as @PetrVep?ek correctly pointed out below. To make your code truly portable you have to be more clever here. This should suffice for many cases though. Note that sizeof(char)is always 1, by definition. The code above assumes sizeof(int)==4.
这假设它int的大小为 4 chars,这并不总是像下面正确指出的@PetrVep?ek 那样给出。为了使您的代码真正可移植,您必须在这里更加聪明。不过,这对于许多情况应该足够了。请注意,根据定义,sizeof(char)始终1为 。上面的代码假设sizeof(int)==4.
回答by pr1268
Not during compile time, but perhaps during runtime. Here's a C function I wrote to determine endianness:
不是在编译时,而是在运行时。这是我编写的用于确定字节序的 C 函数:
/* 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);
}
回答by pr1268
From Finally, one-line endianness detection in the C preprocessor:
#include <stdint.h>
#define IS_BIG_ENDIAN (*(uint16_t *)"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;
\xff" < 0x100)
Any decent optimizer will resolve this at compile-time. gcc does at -O1.
任何体面的优化器都会在编译时解决这个问题。gcc 在-O1.
Of course stdint.his C99. For ANSI/C89 portability see Doug Gwyn's Instant C9xlibrary.
当然stdint.h是C99。有关 ANSI/C89 可移植性,请参阅 Doug Gwyn 的Instant C9x库。
回答by Patrick Schlüter
I once used a construct like this one:
我曾经使用过这样的构造:
typedef union {
uint32_t word;
uint8_t bytes[4];
} byte_check;
gcc with -O2 was able to make it completely compile time. That means, the HI_BYTEand LO_BYTEvariables were replaced entirely and even the pByte acces was replaced in the assembler by the equivalent of *(unit16_t *pByte) = 0x1020;.
带有 -O2 的 gcc 能够使其完全编译。这意味着,HI_BYTE和LO_BYTE变量被完全替换,甚至 pByte 访问在汇编程序中也被替换为*(unit16_t *pByte) = 0x1020;.
It's as compile time as it gets.
编译时间和它一样。
回答by Christoffer
To my knowledge no, not during compile time.
据我所知,不,不是在编译时。
At run-time, you can do trivial checks such as setting a multi-byte value to a known bit string and inspect what bytes that results in. For instance using a union,
在运行时,你可以做一些简单的检查,比如将一个多字节值设置为一个已知的位串并检查结果是什么字节。例如使用联合,
uint32_t word;
uint8_t * bytes = &word;
or casting,
或铸造,
INCLUDE(TestBigEndian)
TEST_BIG_ENDIAN(ENDIAN)
IF (ENDIAN)
# big endian
ELSE (ENDIAN)
# little endian
ENDIF (ENDIAN)
Please note that for completely portable endianness checks, you need to take into account both big-endian, little-endian and mixed-endian systems.
请注意,对于完全可移植的字节序检查,您需要同时考虑大端、小端和混合端系统。
回答by Like
Use CMake TestBigEndianas
使用 CMake TestBigEndian作为
##代码##
![C语言 检查目录是否存在的便携式方法 [Windows/Linux, C]](/res/img/loading.gif)