我已经搜索了宏以确定机器上的字节顺序,并且没有为此找到任何标准的预处理器宏,但很多解决方案在运行时都这样做。 为什么我应该在运行时检测到endianess?
如果我这样做的话:
#ifdef LITTLE_ENDIAN
inline int swap(int& x) {
// do swap anyhow
return swapped;
}
#elif BIG_ENDIAN
inline int& swap(int& x) { return x; }
#else
#error "some blabla"
#endif
int main() {
int x = 0x1234;
int y = swap(x);
return 0;
}
编译器只生成一个函数。
但如果我这样做(见predef.endian):
enum {
ENDIAN_UNKNOWN,
ENDIAN_BIG,
ENDIAN_LITTLE,
ENDIAN_BIG_WORD, /* Middle-endian, Honeywell 316 style */
ENDIAN_LITTLE_WORD /* Middle-endian, PDP-11 style */
};
int endianness(void)
{
uint8_t buffer[4];
buffer[0] = 0x00;
buffer[1] = 0x01;
buffer[2] = 0x02;
buffer[3] = 0x03;
switch (*((uint32_t *)buffer)) {
case 0x00010203: return ENDIAN_BIG;
case 0x03020100: return ENDIAN_LITTLE;
case 0x02030001: return ENDIAN_BIG_WORD;
case 0x01000302: return ENDIAN_LITTLE_WORD;
default: return ENDIAN_UNKNOWN;
}
int swap(int& x) {
switch(endianess()) {
case ENDIAN_BIG:
return x;
break;
case LITTLE_ENDIAN:
// do swap
return swapped;
break;
default:
// error blabla
}
// do swap anyhow
}
编译器生成检测代码。
我不明白,我为什么要这样做?
如果我有代码,为小端机器编译,整个代码是为小端生成的,如果我尝试在big-endian机器上运行这样的代码(在arm {{等双端机器上) 3}})整个代码是为小端机器编译的。以及所有其他声明int也是le。
// compiled on little endian
uint32_t 0x1234; // 0x1234 constant literal
// should result 34120000 on BE
答案 0 :(得分:5)
实际上,SOFTWARE可以设置系统是(当前正在运行)小端模式还是大端模式。大多数系统仅支持在特殊情况下的切换,而不是(幸运的是系统程序员等)任意来回切换。但是可以想象支持可执行文件定义该特定可执行文件是以LE模式还是BE模式运行。在这种情况下,您不能依赖于选择它的操作系统和处理器模型......
另一方面,如果仅硬件EVER支持一个字节序(例如x86的不同形式),那么我认为不需要在运行时检查。你知道它是小端,就是这样。系统包含检查字节序列的代码,并带有转换方法以从大端转换为小端,这是浪费(在性能和代码大小方面)。
答案 1 :(得分:3)
编译时的稳健字节序检测不一定可行。有些平台的endianess甚至可以在同一个二进制文件的运行之间发生变化。
答案 2 :(得分:2)
我认为在运行时检测字节序的唯一好处是你不必乱用宏。正如您已经注意到的那样,没有标准宏说明您正在编译代码的机器的endiannes是什么,因此您必须自己定义一些内容并将其传递给编译器,或者根据指示架构的其他标志有条件地定义它/操作系统,如:
#ifdef _this_system_
#define LITTLE_ENDIAN
#endif
#ifdef _that_system_
#define BIG_ENDIAN
#endif
但重复多次,对于每种可能的架构,这都是凌乱且容易出错的。在运行时检查它更容易,更安全。我知道,这看起来很傻,但它更实用。