我尝试了一种可移植的方法,以确保在编译时使用C++11生成特定于endian的代码,但是我目前只有一台带有Windows的计算机需要测试。正因为如此,我在测试代码的地方数量上有点有限。另外,有没有人能够提供一些最佳实践或技巧,不同的方法来改善这一点?我的意图是在一个很小的数学库中使用它,在这个库中,序列化是一个相当高的优先级。
函数本身相当简单。它检查数组的值,以确定哪个字节放在第一位。然后,它通过枚举返回一个常量值,表示目标机器的endianness。如果一切正常工作,那么这段代码可以替换任何运行时检查,这些运行时检查是我或其他人用于endian检查的。
/*
* 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(数组中的第一个显式设置值)。
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.
}因此,在研究了如何将比特存储在不同的系统中之后,我终于意识到,我可能只需要使用一个比特来测试endianness。它看起来不像使用数组那么容易出错,而且我仍然在我的Windows框中得到了正确的答案。
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()发布于 2014-03-29 07:57:11
只有几点:
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。HL_LITTLE_ENDIAN、HL_BIG_ENDIAN等使用花哨的值。您可以使用1、2等,而不是0x03020100、0x00010203等。发布于 2014-03-29 17:42:47
我要改变这一点:
static constexpr uint8_t endianValues[4] = {0, 1, 2, 3};对此:
static const uint32_t value = HL_LITTLE_ENDIAN; // 0x03020100
static const uint8_t* endianValues = (uint8_t*)&value;或者,您可以更改getEndianOrder函数以将endianValues数组读取为uint32,但您必须添加一个预处理器指令(#pragma),以确保将其放置在一个与4个字节对齐的内存地址中(并且它本身可能会产生一些平台依赖问题,这与这里开始的目标非常不同):
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;
}发布于 2016-05-05 22:15:30
您必须使用预定义的编译器宏(\__BIG_ENDIAN__或\__LITTLE_ENDIAN__与clang,或\__BYTE_ORDER__与gcc)。
提到的其他编译器宏技巧只会检测您正在编译的体系结构的特性,而不会检测您正在为其编译的体系结构的endianness,因此这样的操作是错误的:
\#define IS_BIG_ENDIAN ('\x01\x02\x03\x04' == 0x01020304)https://codereview.stackexchange.com/questions/45675
复制相似问题