首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >编译时检查endianness

编译时检查endianness
EN

Code Review用户
提问于 2014-03-29 06:34:30
回答 3查看 12.6K关注 0票数 5

我尝试了一种可移植的方法,以确保在编译时使用C++11生成特定于endian的代码,但是我目前只有一台带有Windows的计算机需要测试。正因为如此,我在测试代码的地方数量上有点有限。另外,有没有人能够提供一些最佳实践或技巧,不同的方法来改善这一点?我的意图是在一个很小的数学库中使用它,在这个库中,序列化是一个相当高的优先级。

函数本身相当简单。它检查数组的值,以确定哪个字节放在第一位。然后,它通过枚举返回一个常量值,表示目标机器的endianness。如果一切正常工作,那么这段代码可以替换任何运行时检查,这些运行时检查是我或其他人用于endian检查的。

代码语言:javascript
复制
/* 
 * A simple compile-time endian test
 * g++ -std=c++11 -Wall -Werror -Wextra -pedantic -pedantic-errors endian.cpp -o endian
 *
 * This can be used with specialized template functions, classes, and class
 * methods in order better tailor code and reduce reliance on runtime
 * checking systems.
 */

#include <cstdint>
#include <iostream>

/**
 * hl_endianness
 *
 * This enumeration can be placed into templated objects in order to generate
 * compile-time code based on a program's target endianness.
 *
 * The values placed in this enum are used just in case the need arises in
 * order to manually compare them against the number order in the
 * endianValues[] array.
 */
enum hl_endianness : uint32_t {
    HL_LITTLE_ENDIAN   = 0x03020100,
    HL_BIG_ENDIAN      = 0x00010203,
    HL_PDP_ENDIAN      = 0x01000302,
    HL_UNKNOWN_ENDIAN  = 0xFFFFFFFF
};

/**
 * A constant array used to determine a program's target endianness. The
 * values
 *  in this array can be compared against the values placed in the
 * hl_endianness enumeration.
 */
static constexpr uint8_t endianValues[4] = {0, 1, 2, 3};

/**
 * A simple function that can be used to help determine a program's endianness
 * at compile-time.
 */
constexpr hl_endianness getEndianOrder() {
    return
        (0x00 == endianValues[0])           // If Little Endian Byte Order,
            ? HL_LITTLE_ENDIAN              // return 0 for little endian.
            : (0x03 == endianValues[0])     // Else if Big Endian Byte Order,
                ? HL_BIG_ENDIAN             // return 1 for big endian.
                : (0x02 == endianValues[0]) // Else if PDP Endian Byte Order,
                    ? HL_PDP_ENDIAN         // return 2 for pdp endian.
                    : HL_UNKNOWN_ENDIAN;    // Else return -1 for wtf endian.
}

#define HL_ENDIANNESS getEndianOrder()

/*
 * Test program
 */
int main() {
    #if defined _WIN32 || defined _WIN64
        static_assert(
            HL_ENDIANNESS == HL_LITTLE_ENDIAN,
            "Aren't Windows programs Little-Endian?"
        );
    #endif

    constexpr hl_endianness endianness = HL_ENDIANNESS;

    std::cout << "This machine is: ";

    switch (endianness) {
        case HL_LITTLE_ENDIAN:
            std::cout << "LITTLE";
            break;
        case HL_BIG_ENDIAN:
            std::cout << "BIG";
            break;
        case HL_PDP_ENDIAN:
            std::cout << "PDP";
            break;
        case HL_UNKNOWN_ENDIAN:
        default:
            std::cout << "UNKNOWN";
    }

    std::cout << " endian" << std::endl;
}

编辑:

我可以尝试去引用指向endianValues数组的指针偏移量,但是我仍然不确定它是否会最终默认为0(数组中的第一个显式设置值)。

代码语言:javascript
复制
constexpr hl_endianness getEndianOrder() {
    return
        (0x00 == *endianValues)           // If Little Endian Byte Order,
            ? HL_LITTLE_ENDIAN              // return 0 for little endian.
            : (0x03 == *endianValues)     // Else if Big Endian Byte Order,
                ? HL_BIG_ENDIAN             // return 1 for big endian.
                : (0x02 == *endianValues) // Else if PDP Endian Byte Order,
                    ? HL_PDP_ENDIAN         // return 2 for pdp endian.
                    : HL_UNKNOWN_ENDIAN;    // Else return -1 for wtf endian.
}

编辑#2

因此,在研究了如何将比特存储在不同的系统中之后,我终于意识到,我可能只需要使用一个比特来测试endianness。它看起来不像使用数组那么容易出错,而且我仍然在我的Windows框中得到了正确的答案。

代码语言:javascript
复制
enum hl_endianness : uint32_t {
    HL_LITTLE_ENDIAN   = 0x00000001,
    HL_BIG_ENDIAN      = 0x01000000,
    HL_PDP_ENDIAN      = 0x00010000,
    HL_UNKNOWN_ENDIAN  = 0xFFFFFFFF
};

/**
 * A simple function that can be used to help determine a program's endianness
 * at compile-time.
 */
constexpr hl_endianness getEndianOrder() {
    return
        ((1 & 0xFFFFFFFF) == HL_LITTLE_ENDIAN)
            ? HL_LITTLE_ENDIAN
            : ((1 & 0xFFFFFFFF) == HL_BIG_ENDIAN)
                ? HL_BIG_ENDIAN
                : ((1 & 0xFFFFFFFF) == HL_PDP_ENDIAN)
                    ? HL_PDP_ENDIAN
                    : HL_UNKNOWN_ENDIAN;
}

#define HL_ENDIANNESS getEndianOrder()
EN

回答 3

Code Review用户

发布于 2014-03-29 07:57:11

只有几点:

  1. Endian-ness一般不是基于操作系统,而是基于处理器。例如,英特尔的x86处理器是小端的,不管它运行的是Windows还是Linux。
  2. 您的代码将始终返回HL_LITTLE_ENDIAN。为什么?因为如果静态uint8_t endianValues4. = {0,1,2,3};那么endianValues[0] == 0将始终为真!假设你有char x4. = {'c','o','d','e'};你不认为x[0] == 'e'而不是x[0] == 'c'会令人震惊吗?标准的方法是使用联合。类似于以下内容: union endian_tester { uint32_t n;uint8_t p4.;};const endian_tester endian_tester sample = {0x01020304};//这将初始化.n constexpr hl_endianness getEndianOrder() { like (0x04 == sample.p0) / If Little Endian Byte Order,HL_LITTLE_ENDIAN:(0x01 == sample.p0) //如果大端字节命令,?HL_BIG_ENDIAN:(0x02 == sample.p0) // Else如果PDP端字节顺序,.(等)请注意,在我的VisualStudio2013Express版本中并不完全支持constexpr
  3. 我不清楚为什么您需要为HL_LITTLE_ENDIANHL_BIG_ENDIAN等使用花哨的值。您可以使用1、2等,而不是0x03020100、0x00010203等。
  4. 关于堆栈溢出(在C++程序中以编程方式检测endianness)的相关问题
票数 4
EN

Code Review用户

发布于 2014-03-29 17:42:47

我要改变这一点:

代码语言:javascript
复制
static constexpr uint8_t endianValues[4] = {0, 1, 2, 3};

对此:

代码语言:javascript
复制
static const uint32_t value = HL_LITTLE_ENDIAN; // 0x03020100
static const uint8_t* endianValues = (uint8_t*)&value;

或者,您可以更改getEndianOrder函数以将endianValues数组读取为uint32,但您必须添加一个预处理器指令(#pragma),以确保将其放置在一个与4个字节对齐的内存地址中(并且它本身可能会产生一些平台依赖问题,这与这里开始的目标非常不同):

代码语言:javascript
复制
constexpr hl_endianness getEndianOrder()
{
    switch (*(uint32_t*)endianValues))
    {
        case HL_LITTLE_ENDIAN: return HL_LITTLE_ENDIAN;
        case HL_BIG_ENDIAN:    return HL_BIG_ENDIAN;
        case HL_PDP_ENDIAN:    return HL_PDP_ENDIAN;
    }
    return HL_UNKNOWN_ENDIAN;
}
票数 2
EN

Code Review用户

发布于 2016-05-05 22:15:30

您必须使用预定义的编译器宏(\__BIG_ENDIAN__\__LITTLE_ENDIAN__与clang,或\__BYTE_ORDER__与gcc)。

提到的其他编译器宏技巧只会检测您正在编译的体系结构的特性,而不会检测您正在为其编译的体系结构的endianness,因此这样的操作是错误的:

代码语言:javascript
复制
\#define IS_BIG_ENDIAN ('\x01\x02\x03\x04' == 0x01020304)
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/45675

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档