是否有一种编程方法来检测您使用的是大端序还是小端序体系结构?我需要能够编写将在英特尔或PPC系统上执行的代码,并使用完全相同的代码(即,没有条件编译)。


当前回答

c++20解决方案:

constexpr bool compare(auto const c, auto const ...a) noexcept
{
  return [&]<auto ...I>(std::index_sequence<I...>) noexcept
    {
      return ((std::uint8_t(c >> 8 * I) == a) && ...);
    }(std::make_index_sequence<sizeof...(a)>());
}

static constexpr auto is_big_endian_v{
  compare(std::uint32_t(0x01234567), 0x01, 0x23, 0x45, 0x67)
};

static constexpr auto is_little_endian_v{
  compare(std::uint32_t(0x01234567), 0x67, 0x45, 0x23, 0x01)
};

static constexpr auto is_pdp_endian_v{
  compare(std::uint32_t(0x01234567), 0x23, 0x01, 0x67, 0x45)
};

这个任务可以更容易地完成,但是由于某种原因,<bit>头文件并不总是存在。这是一个演示。

其他回答

声明一个int变量:

int variable = 0xFF;

现在使用char*指针指向它的各个部分,并检查这些部分中有什么。

char* startPart = reinterpret_cast<char*>( &variable );
char* endPart = reinterpret_cast<char*>( &variable ) + sizeof( int ) - 1;

根据哪一个指向0xFF字节,现在您可以检测到字节顺序。这需要sizeof(int) > sizeof(char),但对于所讨论的平台绝对是正确的。

我不喜欢基于类型双关的方法——它经常会被编译器警告。这正是工会存在的意义!

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都适用,否则很容易把事情搞砸。

正如前面的答案所述,使用工会技巧。

但是上面建议的方法也存在一些问题。最值得注意的是,对于大多数架构来说,未对齐的内存访问是出了名的慢,一些编译器甚至根本无法识别这样的常量谓词,除非字对齐。

因为仅仅是端序测试很无聊,这里有一个(模板)函数,它将根据您的规范翻转输入/输出的任意整数,而不考虑主机架构。

#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上稍微慢一点(展开&,<<,>>,|每个字节),但仍然不错。

参见Endianness - c级代码说明。

// assuming target architecture is 32-bit = 4-Bytes
enum ENDIANNESS{ LITTLEENDIAN , BIGENDIAN , UNHANDLE };


ENDIANNESS CheckArchEndianalityV1( void )
{
    int Endian = 0x00000001; // assuming target architecture is 32-bit    

    // as Endian = 0x00000001 so MSB (Most Significant Byte) = 0x00 and LSB (Least     Significant Byte) = 0x01
    // casting down to a single byte value LSB discarding higher bytes    

    return (*(char *) &Endian == 0x01) ? LITTLEENDIAN : BIGENDIAN;
} 

你可以通过设置int和屏蔽位来做到这一点,但可能最简单的方法是使用内置的网络字节转换操作(因为网络字节顺序总是大端序)。

if ( htonl(47) == 47 ) {
  // Big endian
} else {
  // Little endian.
}

一点点摆弄可能会更快,但这种方法简单,直接,几乎不可能搞砸。