是否有一种编程方法来检测您使用的是大端序还是小端序体系结构?我需要能够编写将在英特尔或PPC系统上执行的代码,并使用完全相同的代码(即,没有条件编译)。
当前回答
不要使用联合号!
c++不允许通过联合的类型双关语! 从不是最后写入的联合字段读取是未定义的行为! 许多编译器支持这样做作为扩展,但语言不能保证。
更多细节请参见以下答案:
https://stackoverflow.com/a/11996970
只有两个有效的答案可以保证是可移植的。
第一个答案,如果你有一个支持c++ 20的系统, 是从<bit>标头使用std::endian。
C++20 起
constexpr bool is_little_endian = (std::endian::native == std::endian::little);
在c++ 20之前,唯一有效的答案是存储一个整数,然后通过类型双关检查它的第一个字节。 与联合的使用不同,这是c++类型系统明确允许的。
同样重要的是要记住,为了获得最佳的可移植性,应该使用static_cast, 因为reinterpret_cast是实现定义的。
如果程序试图通过非下列类型之一的glvalue访问对象的存储值,则行为未定义: ... char或unsigned char类型。
c++ 11 Onwards
enum class endianness
{
little = 0,
big = 1,
};
inline endianness get_system_endianness()
{
const int value { 0x01 };
const void * address = static_cast<const void *>(&value);
const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
return (*least_significant_address == 0x01) ? endianness::little : endianness::big;
}
c++ 11开始(没有enum)
inline bool is_system_little_endian()
{
const int value { 0x01 };
const void * address = static_cast<const void *>(&value);
const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
return (*least_significant_address == 0x01);
}
c++ 98 / c++ 03
inline bool is_system_little_endian()
{
const int value = 0x01;
const void * address = static_cast<const void *>(&value);
const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
return (*least_significant_address == 0x01);
}
其他回答
参见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 i=1;
char *c=(char*)&i;
bool littleendian=c;
正如Coriiander所指出的,这里的大部分(如果不是全部的话)代码将在编译时被优化掉,因此生成的二进制文件不会在运行时检查“字节顺序”。
据观察,给定的可执行文件不应该以两个不同的字节顺序运行,但我不知道是否总是这样,对我来说,在编译时检查似乎是一种hack。所以我编写了这个函数:
#include <stdint.h>
int* _BE = 0;
int is_big_endian() {
if (_BE == 0) {
uint16_t* teste = (uint16_t*)malloc(4);
*teste = (*teste & 0x01FE) | 0x0100;
uint8_t teste2 = ((uint8_t*) teste)[0];
free(teste);
_BE = (int*)malloc(sizeof(int));
*_BE = (0x01 == teste2);
}
return *_BE;
}
MinGW无法优化这段代码,尽管它确实优化了这里的其他代码。我相信这是因为我保留了分配在较小字节内存上的“随机”值(至少有7位),所以编译器无法知道这个随机值是什么,也不会优化函数。
我还对函数进行了编码,以便只执行一次检查,并为下一次测试存储返回值。
我很惊讶没有人提到预处理器默认定义的宏。但这取决于你的平台;它们比你自己写尾票要干净得多。
例如;如果我们看看GCC定义的内置宏(在x86-64机器上):
:| gcc -dM -E -x c - | grep -i endian
#define __LITTLE_ENDIAN__ 1
在PPC机器上,我得到:
:| gcc -dM -E -x c - | grep -i endian
#define __BIG_ENDIAN__ 1
#define _BIG_ENDIAN 1
(The:| gcc - dm - e -x c - magic打印出所有内置宏。)
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>头文件并不总是存在。这是一个演示。
推荐文章
- 为什么STL如此严重地基于模板而不是继承?
- 查找当前可执行文件的路径,不包含/proc/self/exe
- 有效的方法应用多个过滤器的熊猫数据框架或系列
- 未定义对静态constexpr char的引用[]
- 在c++中,restrict关键字是什么意思?
- c++中类似于java的instanceof
- include_directories和target_include_directories在CMake中的区别是什么?
- std::make_pair与std::pair的构造函数的目的是什么?
- 如何追加一个字符到std::字符串?
- 为什么要在c++中使用嵌套类?
- 如何处理11000行c++源文件?
- 使用g++编译多个.cpp和.h文件
- 如何在c++中追加文本到文本文件?
- 在c++中使用"super
- Mmap () vs.读取块