【问题标题】:what is the benefit of detecting endian at runtime?在运行时检测字节序有什么好处?
【发布时间】:2013-04-19 16:39:51
【问题描述】:

我已经搜索了宏以确定机器上的字节顺序,但没有找到任何标准的处理器宏,但有很多解决方案在运行时这样做。 为什么要在运行时检测字节序?

如果我这样做:

#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
}

编译器生成检测代码。

我不明白,我为什么要这样做?

如果我有代码,为小端机器编译,整个代码都是为小端机器生成的,如果我尝试在大端机器上运行这样的代码(在像 arm @987654322 这样的双端机器上@) 整个代码是为 little-endian 机器编译的。所以所有其他声明,例如int 也是 le。

// compiled on little endian
uint32_t 0x1234;  // 0x1234 constant literal
// should result 34120000 on BE

【问题讨论】:

  • 我假设你的意思是它应该导致 34120000 小端?
  • @MarkB 为什么?在 BE 上执行的 LE 上编译。交换应该是相同的。
  • 是否有任何现代机器仍在使用字交换字节序表示法?或者我可以在编写(反)序列化引擎时忽略它们吗?

标签: c++ endianness


【解决方案1】:

实际上,在某些系统中,SOFTWARE 可以设置系统是(当前运行的)小端模式还是大端模式。大多数系统只支持在特殊情况下进行切换,而不是(幸运的是对于系统程序员等)任意来回切换。但是可以想象支持一个可执行文件定义该特定可执行文件是在 LE 模式下运行还是在 BE 模式下运行。在那种情况下,你不能依赖于挑选出它是什么操作系统和处理器型号......

另一方面,如果仅硬件 EVER 支持一种字节序(例如不同形式的 x86),那么我认为不需要在运行时检查。你知道它是小端,就是这样。让系统包含代码来检查它是哪种字节序,并携带从大字节序转换为小字节序的转换方法是浪费的(在性能和代码大小方面)。

【讨论】:

  • +1 PowerPC 就是这样一种架构。
  • 我知道至少有一些 ARM 和 MIPS 以及现在相当停产的 29K 处理器范围可以配置为“将字节序设置为此”。虽然需要一些仔细的计划才能使它正确,否则您将完全回到杂草丛生的某个地方,并且由于您的代码意外地将一些随机位带入控制寄存器而意外更改它,但我相信这会非常有趣调试。
【解决方案2】:

编译时强大的字节序检测不一定是可能的。在某些平台上,即使在同一二进制文件的运行之间,字节序也可能发生变化。

http://gcc.gnu.org/ml/gcc-help/2007-07/msg00343.html

【讨论】:

  • 好吧不知道。所以它对一些稀有机器很有用,但不适合我用。谢谢
【解决方案3】:

我认为在运行时检测字节顺序的唯一好处是您不必乱用宏。正如您自己注意到的那样,没有标准宏说明您正在编译代码的机器的字节序是什么,因此您必须自己定义一些内容并将其传递给编译器,或者根据其他指示架构的标志有条件地定义它/操作系统,例如:

#ifdef _this_system_
#define LITTLE_ENDIAN
#endif
#ifdef _that_system_
#define BIG_ENDIAN
#endif

但对于每个可能的架构都重复了很多次,这很混乱且容易出错。在运行时检查它更容易、更安全。我知道,这看起来很傻,但确实更实用。

【讨论】:

  • 在处理跨平台项目时,很可能会使用构建系统生成器(AutoTools、CMake、SCons...)。这也可以用于检测字节顺序(例如,通过构建和运行一个小程序)并将适当的定义传递给编译器。
  • 当然,我确信 cmake 和类似的系统可以提供强大的编译时解决方案,所以如果你使用这样的系统,你可以去。
  • @Angew 如果要允许交叉编译,请小心。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
  • 2015-04-25
  • 2017-11-10
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
相关资源
最近更新 更多