我的印象是访问union除最后一个成员之外的成员是UB,但我似乎无法找到一个可靠的参考(除了声称它是UB但没有标准支持的答案).
那么,这是不确定的行为?
可能重复:
C宏定义确定大端或小端机器?
int main()
{
int x = 1;
char *y = (char*)&x;
printf("%c\n",*y+48);
}
Run Code Online (Sandbox Code Playgroud)
如果它是小端,它将打印1.如果它是大端,它将打印0.这是正确的吗?或者将char*设置为int x始终指向最低有效位,而不管字节顺序如何?
是否有一种安全,可移植的方法来确定(在编译期间)我的程序正在编译的平台的字节顺序?我在用C写作
[编辑]感谢您的回答,我决定坚持运行时解决方案!
我做了一些谷歌搜索,在这个问题上找不到任何好文章.在实现我想要与endian无关的应用程序时,我应该注意什么?
我正在Windows上编写用户空间文件系统驱动程序,并且字节顺序转换是我一直在处理的事情,因为这个特定的文件系统总是以little-endian格式存储值,并且驱动程序应该为它们转换它们(如果需要)它是继续前进.但是,我发现自己想知道我是否需要担心字节序转换,因为据我所知,桌面Windows只支持小端架构(IA32,x86-84等),因此,盘上little-endian值非常精细,无法转换.这种观察是否准确,如果是这样,假设Windows将始终在小端硬件上运行通常是可以接受的吗?此外,甚至可能(在2011年)在大端模拟器或其他东西上运行Windows,甚至可以测试字节序问题?
编辑:为了更清楚,我的代码目前的工作方式,我在启动时进行字节顺序检查,然后每次我从磁盘加载一个值,我通过内联函数运行它,使用内在更改字节顺序,如果建筑是大端的.问题是,我不知道我是否可能错过了我需要进行转换的一个或多个地方,最简单的方法是看我搞砸了是在大端架构上运行程序.所以我有兴趣知道(a)是否甚至需要进行这些检查,因为Windows通常不会在小端平台上运行(现在无论如何),以及(b)我如何可能测试我的代码,看到我想不出在大端架构上运行Windows的方法,并且手动反转磁盘上的所有多字节值仍然涉及一个我可能搞砸的手动过程.
我正在研究一种以大端格式将64位值存储到内存中的函数.我希望我能编写可在小端和大端平台上运行的可移植C99代码,并让现代x86编译器bswap自动生成指令而不需要任何内置函数或内在函数.所以我开始使用以下功能:
#include <stdint.h>
void
encode_bigend_u64(uint64_t value, void *vdest) {
uint64_t bigend;
uint8_t *bytes = (uint8_t*)&bigend;
bytes[0] = value >> 56;
bytes[1] = value >> 48;
bytes[2] = value >> 40;
bytes[3] = value >> 32;
bytes[4] = value >> 24;
bytes[5] = value >> 16;
bytes[6] = value >> 8;
bytes[7] = value;
uint64_t *dest = (uint64_t*)vdest;
*dest = bigend;
}
Run Code Online (Sandbox Code Playgroud)
这适用于clang,它将此函数编译为:
bswapq %rdi
movq %rdi, (%rsi)
retq
Run Code Online (Sandbox Code Playgroud)
但是GCC 无法检测到字节交换 …
我正在尝试创建一个C源代码,无论目标系统的字节顺序如何,它都能正确处理I/O.
我选择了"little endian"作为我的I/O约定,这意味着,对于大端CPU,我需要在写入或读取时转换数据.
转换不是问题.我面临的问题是检测字节序,最好是在编译时(因为CPU在执行过程中不会改变字节序...).
到目前为止,我一直在使用这个:
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
...
#else
...
#endif
Run Code Online (Sandbox Code Playgroud)
它被记录为GCC预定义的宏,而Visual似乎也理解它.
但是,我收到报告说某些big_endian系统(PowerPC)的检查失败了.
所以,我正在寻找一个万无一失的解决方案,确保无论编译器和目标系统如何都能正确检测到字节顺序.好吧,他们中的大多数至少......
[编辑]:提出的大多数解决方案都依赖于"运行时测试".编译期间编译器有时可以正确评估这些测试,因此不会产生实际的运行时性能.
然而,用某种<< if (0) { ... } else { ... }>> 分支是不够的.在当前的代码实现中,变量和函数声明依赖于big_endian检测.使用if语句无法更改这些内容.
嗯,显然,有后备计划,即重写代码......
我宁愿避免这种情况,但是,它看起来像是一个越来越少的希望......
[编辑2]:我通过深度修改代码测试了"运行时测试".尽管他们正确地完成了工作,但这些测试也会影响性能.
我期待着,因为测试具有可预测的输出,编译器可以消除坏分支.但不幸的是,它并不是一直有效.MSVC是一个很好的编译器,并且成功地消除了坏分支,但是GCC的结果是混合的,这取决于版本,测试类型,以及对64位比对32位的影响更大.
真奇怪.而且这也意味着无法确保编译器处理运行时测试.
编辑3:这些天,我正在使用编译时常量联合,期望编译器将其解析为明确的是/否信号.它运作得很好:https: //godbolt.org/g/DAafKo
我已就此主题提出了很多问题,但到目前为止找不到任何解决方案.这里提到了一个自然的解决方案:在编译时确定字节序.
但是,评论中提到的相关问题和答案相同.
通过一些修改,我能够在-std=c++11没有任何警告的情况下使用g ++和clang ++()编译类似的解决方案.
static_assert(sizeof(char) == 1, "sizeof(char) != 1");
union U1
{
int i;
char c[sizeof(int)];
};
union U2
{
char c[sizeof(int)];
int i;
};
constexpr U1 u1 = {1};
constexpr U2 u2 = {{1}};
constexpr bool IsLittleEndian ()
{
return u1.i == u2.c[0]; // ignore different type comparison
}
static_assert(IsLittleEndian(), "The machine is BIG endian");
Run Code Online (Sandbox Code Playgroud)
演示.
这可以被认为是决定字节序的确定性方法还是错过类型惩罚或其他什么?
仅使用C库将颜色HEX代码转换为纯c中的RGB(不含C++,模板等)RGB结构可能是这样的 - > typedef struct RGB {double r; 双g; 双b; } RGB1; 函数应该返回RGB1
endianness ×8
c ×6
c++ ×3
compile-time ×2
byte ×1
c++11 ×1
colors ×1
gcc ×1
hex ×1
rgb ×1
type-punning ×1
unions ×1
windows ×1
x86 ×1