是否有一种编程方法来检测您使用的是大端序还是小端序体系结构?我需要能够编写将在英特尔或PPC系统上执行的代码,并使用完全相同的代码(即,没有条件编译)。
当前回答
除非端标头只支持gcc,否则它提供了可以使用的宏。
#include "endian.h"
...
if (__BYTE_ORDER == __LITTLE_ENDIAN) { ... }
else if (__BYTE_ORDER == __BIG_ENDIAN) { ... }
else { throw std::runtime_error("Sorry, this version does not support PDP Endian!");
...
其他回答
正如前面的答案所述,使用工会技巧。
但是上面建议的方法也存在一些问题。最值得注意的是,对于大多数架构来说,未对齐的内存访问是出了名的慢,一些编译器甚至根本无法识别这样的常量谓词,除非字对齐。
因为仅仅是端序测试很无聊,这里有一个(模板)函数,它将根据您的规范翻转输入/输出的任意整数,而不考虑主机架构。
#include <stdint.h>
#define BIG_ENDIAN 1
#define LITTLE_ENDIAN 0
template <typename T>
T endian(T w, uint32_t endian)
{
// This gets optimized out into if (endian == host_endian) return w;
union { uint64_t quad; uint32_t islittle; } t;
t.quad = 1;
if (t.islittle ^ endian) return w;
T r = 0;
// Decent compilers will unroll this (GCC)
// or even convert straight into single bswap (Clang)
for (int i = 0; i < sizeof(r); i++) {
r <<= 8;
r |= w & 0xff;
w >>= 8;
}
return r;
};
用法:
要将给定的端序转换为主机,请使用:
Host = endian(source, endian_of_source)
要将主机端序转换为给定端序,请使用:
输出= endian(hostsource, endian_you_want_to_output)
生成的代码与在Clang上编写手动程序集一样快,在GCC上稍微慢一点(展开&,<<,>>,|每个字节),但仍然不错。
这是另一个C版本。它定义了一个名为wickd_cast()的宏,用于通过C99联合字面值和非标准__typeof__操作符实现内联类型双关语。
#include <limits.h>
#if UCHAR_MAX == UINT_MAX
#error endianness irrelevant as sizeof(int) == 1
#endif
#define wicked_cast(TYPE, VALUE) \
(((union { __typeof__(VALUE) src; TYPE dest; }){ .src = VALUE }).dest)
_Bool is_little_endian(void)
{
return wicked_cast(unsigned char, 1u);
}
如果整数是单字节值,则字节顺序没有意义,并将生成编译时错误。
除非你使用的框架已经移植到PPC和英特尔处理器上,否则你将不得不进行条件编译,因为PPC和英特尔平台拥有完全不同的硬件架构、管道、总线等。这使得两者的程序集代码完全不同。
至于查找字节序,请执行以下操作:
short temp = 0x1234;
char* tempChar = (char*)&temp;
您可以让tempChar为0x12或0x34,从中可以知道字节序。
我不喜欢基于类型双关的方法——它经常会被编译器警告。这正是工会存在的意义!
bool is_big_endian(void)
{
union {
uint32_t i;
char c[4];
} bint = {0x01020304};
return bint.c[0] == 1;
}
这个原则等同于其他人建议的类型大小写,但这更清楚——并且根据C99,它保证是正确的。与直接指针强制转换相比,GCC更喜欢这种方法。
这也比在编译时修复字节序要好得多——对于支持多架构的操作系统(例如Mac OS X上的胖二进制),这对ppc/i386都适用,否则很容易把事情搞砸。
这通常在编译时(特别是出于性能原因)通过使用编译器提供的头文件或创建自己的头文件来完成。在Linux上,你有头文件“/usr/include/ endan .h”。