宏定义确定大端还是小端机?
是否有一行宏定义来确定机器的字节顺序?我正在使用以下代码,但将其转换为宏会太长:
unsigned char test_endian( void )
{
int test_var = 1;
unsigned char *test_endian = (unsigned char*)&test_var;
return (test_endian[0] == 0);
}
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(24)
支持任意字节顺序的代码,准备放入名为
order32.h
的文件中:您可以通过以下方式检查小端系统:
Code supporting arbitrary byte orders, ready to be put into a file called
order32.h
:You would check for little endian systems via
如果您有一个支持 C99 复合文字的编译器:
或:
但一般来说,您应该尝试编写不依赖于主机平台字节序的代码。
ntohl()
与主机字节序无关的实现示例:If you have a compiler that supports C99 compound literals:
or:
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()
:没有标准,但在许多系统上,包括
将为您提供一些需要查找的定义。There is no standard, but on many systems including
<endian.h>
will give you some defines to look for.要在运行时检测字节顺序,您必须能够引用内存。如果您坚持使用标准 C,则在内存中声明变量需要一个语句,但返回一个值需要一个表达式。我不知道如何在单个宏中执行此操作 - 这就是 gcc 具有扩展名的原因 :-)
如果您愿意拥有 .h 文件,则可以定义
,然后可以使用
ENDIANNESS 宏,如你所愿。
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 :-)
If you're willing to have a .h file, you can define
and then you can use the
ENDIANNESS
macro as you will.如果您只想依赖预处理器,则必须找出预定义符号的列表。预处理器算术没有寻址的概念。
Mac 上的 GCC 定义了
__LITTLE_ENDIAN__
或__BIG_ENDIAN__
然后,您可以根据平台检测添加更多预处理器条件指令,例如
#ifdef _WIN32
代码>等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 Mac defines
__LITTLE_ENDIAN__
or__BIG_ENDIAN__
Then, you can add more preprocessor conditional directives based on platform detection like
#ifdef _WIN32
etc.我相信这就是我们所要求的。
我只在 msvc 下的小端机器上测试了这个。
请有人在大端机器上确认。
作为旁注(特定于编译器),使用激进的编译器,您可以使用“死代码消除”优化来实现与编译时
#if
相同的效果,如下所示:编译器在编译时识别常量值,完全删除
if (false) { ... }
中的代码,并替换类似if (true) { foo(); 的代码。 }
和foo();
最坏的情况:编译器不进行优化,您仍然会得到正确的代码,但速度会慢一些。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.
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
#if
like so: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 likeif (true) { foo(); }
withfoo();
The worst case scenario: the compiler does not do the optimization, you still get correct code but a bit slower.如果您正在寻找编译时测试并且正在使用 gcc,您可以执行以下操作:
请参阅 gcc 文档 了解更多信息。
If you are looking for a compile time test and you are using gcc, you can do:
See gcc documentation for more information.
事实上,您可以使用复合文字 (C99) 来访问临时对象的内存:
GCC 将在编译时评估该文字。
You can in fact access the memory of a temporary object by using a compound literal (C99):
Which GCC will evaluate at compile time.
如果你转储预处理器#defines,
你通常可以找到对你有帮助的东西。具有编译时逻辑。
然而,不同的编译器可能有不同的定义。
If you dump the preprocessor #defines
You can usually find stuff that will help you. With compile time logic.
Various compilers may have different defines however.
“C 网络库”提供了处理字节序的函数。即 htons()、htonl()、ntohs() 和 ntohl() ...其中 n 是“网络”(即大端字节序),h 是“主机”(即运行该网络的机器的字节序)代码)。
这些明显的“函数”(通常)被定义为宏[参见],因此使用它们没有运行时开销。
以下宏使用这些“函数”来评估字节序。
另外:
我唯一需要知道系统的字节序是当我将一个变量[到文件/其他]写出时,该变量可能会被另一个未知字节序的系统读入(对于交叉字节序) -平台兼容性)...在这些情况下,您可能更喜欢直接使用 endian 函数:
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).
These apparent 'functions' are (commonly) defined as macros [see <netinet/in.h>], so there is no runtime overhead for using them.
The following macros use these 'functions' to evaluate endian'ness.
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:
使用内联函数而不是宏。此外,您需要在内存中存储一些内容,这是宏的一个不太好的副作用。
您可以使用静态或全局变量将其转换为短宏,如下所示:
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:
虽然没有可移植的 #define 或依赖的东西,但平台确实提供了用于与“主机”字节序相互转换的标准函数。
通常,您使用“网络字节序”(BIG 字节序)进行存储(到磁盘或网络),并使用主机字节序(在 x86 上为小字节序)进行本地计算)。您可以使用
htons()
和ntohs()
及其朋友在两者之间进行转换。Whilst there is no portable #define or something to rely upon, platforms do provide standard functions for converting to and from your 'host' endian.
Generally, you do storage - to disk, or network - using 'network endian', which is BIG endian, and local computation using host endian (which on x86 is LITTLE endian). You use
htons()
andntohs()
and friends to convert between the two.不要忘记字节顺序并不是故事的全部 -
char
的大小可能不是 8 位(例如 DSP),不保证二进制补码否定(例如 Cray),可能需要严格对齐(例如,SPARC,ARM 在未对齐时也会跳入中端),等等。针对特定的CPU 架构可能是一个更好的主意。
例如:
请注意,不幸的是,该解决方案也不是超可移植的,因为它取决于特定于编译器的定义(没有标准,但是 这里是此类定义的一个很好的汇编)。
Don't forget that endianness is not the whole story - the size of
char
might not be 8 bits (e.g. DSP's), two's complement negation is not guaranteed (e.g. Cray), strict alignment might be required (e.g. SPARC, also ARM springs into middle-endian when unaligned), etc, etc.It might be a better idea to target a specific CPU architecture instead.
For example:
Note that this solution is also not ultra-portable unfortunately, as it depends on compiler-specific definitions (there is no standard, but here's a nice compilation of such definitions).
这个问题对于cpp来说也是实际的,所以我在这里问。
仅
#if __cplusplus > 201703L
欲了解更多信息:https://en.cppreference.com/w /cpp/类型/字节序
This question is actual for cpp too, so I asked here.
ONLY
#if __cplusplus > 201703L
For more info: https://en.cppreference.com/w/cpp/types/endian
试试这个:
Try this:
在 C++20 中,头文件
中引入了枚举std::endian
:https://en.cppreference.com/w/cpp/types/endian
In C++20 an enum
std::endian
in the header<bit>
was introduced:https://en.cppreference.com/w/cpp/types/endian
请注意,这里的大多数答案都是不可移植的,因为今天的编译器将在编译时评估这些答案(取决于优化)并根据特定的字节顺序返回特定值,而实际的机器字节顺序可能有所不同。测试字节顺序的值永远不会到达系统内存,因此无论实际字节顺序如何,实际执行的代码都将返回相同的结果。
对于示例,在 ARM Cortex-M3 中,实现的字节顺序将反映在状态位 AIRCR.ENDIANNESS 中,并且编译器在编译时无法知道该值。
这里建议的一些答案的编译输出:
https://godbolt.org/z/GJGNE2 for 这个答案,
https://godbolt.org/z/Yv-pyJ for 这个答案,等等在。
要解决这个问题,您需要使用
易失性
限定符。Yogeesh H T
的答案是最接近当今现实生活使用情况的答案,但由于Christoph
建议了更全面的解决方案,因此对他的 answer 将使答案完整,只需将易失性
添加到联合声明中:static const 易失性联合
。这将确保存储和读取内存,这是确定字节顺序所必需的。
Please pay attention that most of the answers here are not portable, since compilers today will evaluate those answers in compilation time (depends on the optimization) and return a specific value based on a specific endianness, while the actual machine endianness can differ. The values on which the endianness is tested, won't never reach the system memory thus the real executed code will return the same result regardless of the actual endianness.
For example, in ARM Cortex-M3 the implemented endianness will reflect in a status bit AIRCR.ENDIANNESS and compiler cannot know this value in compile time.
Compilation output for some of the answers suggested here:
https://godbolt.org/z/GJGNE2 for this answer,
https://godbolt.org/z/Yv-pyJ for this answer, and so on.
To solve it you will need to use the
volatile
qualifier.Yogeesh H T
's answer is the closest one for today's real life usage, but sinceChristoph
suggests more comprehensive solution, a slight fix to his answer would make the answer complete, just addvolatile
to the union declaration:static const volatile union
.This would assure storing and reading from memory, which is needed to determine endianness.
如果您的编译器支持复合文字并且您明确不使用 C++,则可以使用
这不需要声明任何运行时变量,我认为这使得它比大多数其他解决方案更干净
If your compiler supports compound literals and you are pointedly not using C++ you can use
This doesn't require the declaration of any runtime variables, which I think makes it a good deal cleaner than most of the other solutions
工作原理
演示
How It Works
Demo
如果 boost 可用,那么您可以使用
Boost.Predef
其中包含各种预定义的目标平台的宏,包括字节顺序 (BOOST_ENDIAN_*
)。是的 boost 通常被认为是一个 C++ 库,但这是一个可以使用的预处理器标头C 也是如此!它允许您在编译时中便携式地检测字节序例如,
更多详细信息可以在
BOOST_ENDIAN_*
sectionDemo on Godbolt
Note that it obviously can不检测可以在运行时期间更改字节序的双端平台
If boost is available then you can use
Boost.Predef
which contains various predefined macros for the target platform including endianness (BOOST_ENDIAN_*
). Yes boost is often thought as a C++ library, but this one is a preprocessor header that works with C as well! It allows you to detect endian in compile time portablyFor example
More details can be found in
BOOST_ENDIAN_*
sectionDemo on Godbolt
Note that it obviously can't detect bi-endian platforms where the endian can be changed during runtime
我的答案并不像所问的那样,但是找到您的系统是小端还是大端非常简单?
代码:
My answer is not as asked but It is really simple to find if your system is little endian or big endian?
Code:
用于检查系统是小字节序还是大字节序的 C 代码。
C Code for checking whether a system is little-endian or big-indian.
用于查找字节序
或的宏
Macro to find endiannes
or