what is the benefit of detecting endian at runtime

2020-07-19 03:52发布

问题:

i've searched for macro's to determine endianess on a machine and didn't found any standard proprocessor macros for this, but a lot of solutions doing that on runtime. why should i detect endianess at runtime?

if i do somthing like that:

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

the compiler will generate only one function.

but if i do it like (see 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
}

the compiler generates code for the detection.

i don't get it, why should i do this?

if i have code, compiled for a little-endian machine, the whole code is generated for little endian, and if i try to run such code on a big-endian machine (on a bi-endian machine like arm wiki:bi-endian) the whole code is compiled for a little-endian machine. so all other declarations of e.g. int are also le.

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

回答1:

There are actually systems where SOFTWARE can set whether the system is (currently running in) little or big endian mode. Most systems only support switching that under special circumstances, and not (fortunately for system programmers and such) switching back and forth arbitrarily. But it would be conceivable to support that an executable file defines whether that particular executable runs in LE or BE mode. In that case, you can't rely on picking out what OS and processor model it is...

On the other hand, if the hardware only EVER supports one endianness (e.g. x86 in its different forms), then I don't see a need to check at runtime. You know it's little endian, and that's it. It is wasteful (in terms of performance and code-size) to have the system contain code to check which endianness it is, and carry around conversion methods to convert from big endian to little endian.



回答2:

Robust endian detection at compile time isn't necessarily possible. There are platforms where endianess can change even between runs of the same binary.

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



回答3:

I think the only benefit of detecting endianness in runtime is that you don't have to mess around with macros. As you have noticed yourself, there is no standard macro saying what is the endiannes of the machine you are compiling your code on, so you must define something yourself and pass it to the compiler, or define it conditionally depending on other flags indicating architecture/operating system, something like:

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

but repeated many times, for every possible architecture, which is messy and error prone. It is easier and safer to check it in runtime. I know, it seems silly, but it is really more practical.