【发布时间】:2019-03-08 22:52:22
【问题描述】:
我见过的从缓冲区读取双倍已知字节序到平台字节序的所有示例都涉及检测当前平台的字节序并在必要时执行字节交换。
另一方面,除了使用位移位的整数 (one such example),我还看到了另一种做同样事情的方法。
这让我想到可以使用联合和位移技术从缓冲区读取双精度数(和浮点数),并且快速测试实现似乎有效(至少在 x86_64 上使用 clang):
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
double read_double(char * buffer, bool le) {
union {
double d;
uint64_t i;
} data;
data.i = 0;
int off = le ? 0 : 7;
int add = le ? 1 : -1;
for (int i = 0; i < 8; i++) {
data.i |= ((uint64_t)(buffer[off] & 0xFF) << (i * 8));
off += add;
}
return data.d;
}
int main() {
char buffer_le[] = {0x6E, 0x86, 0x1B, 0xF0, 0xF9, 0x21, 0x09, 0x40};
printf("%f\n", read_double(buffer_le, true)); // 3.141590
char buffer_be[] = {0x40, 0x09, 0x21, 0xF9, 0xF0, 0x1B, 0x86, 0x6E};
printf("%f\n", read_double(buffer_be, false)); // 3.141590
return 0;
}
我的问题是,这是一种安全的方法吗?或者这里是否涉及未定义的行为?或者,如果 this 和 byte-swap 方法都涉及未定义的行为,那么一个比另一个更安全吗?
【问题讨论】:
-
@EugeneSh。 memcpy is the way to avoid strict aliasing 你是否有一个有效的替身是另一回事,但我认为标准不能保证这一点。
-
@EugeneSh.:C 2018 6.5.2.3 3 允许通过联合重新解释,脚注 99 明确确认这是文本的预期含义。
-
@EugeneSh.: C 2018,C 2011,C 1999中的子句和段落是一样的。注释在C 2018中是99,在C 2011中是95。C 1999没有注释.
-
@EugeneSh.:通过字符类型修改对象的字节不会违反别名规则。根据 C 2018 6.5 7,“对象的存储值只能由……[各种类型]或字符类型访问。”根据 3.1 1,“访问”意味着“读取或修改对象的值”。
-
@EugeneSh.:当人们通过
structure.member表达式读取联合的成员时,我们正在通过自己的类型读取作为该成员的对象,这当然与自身兼容。所以它不违反别名规则。如果有这样的规则但没有,它可能会违反关于访问最后写入成员以外的成员的规则。
标签: c decode endianness undefined-behavior decoding