取消引用类型punned指针将打破严格的混叠规则:将字节数组转换为数字

dereferencing type-punned pointer will break strict-aliasing rules: array of bytes to a number

本文关键字:字节 规则 字节数 数组 转换 数字 指针 punned 引用类型 取消      更新时间:2023-10-16

我已经读过很多关于这个警告的问题(取消引用类型的punned指针将打破严格的混叠规则,取消引用类型punned指示器将打破严格混叠规则[-Wstrict aliasing],什么是严格混叠规则?,"取消引用类型punned指针会打破严格混迭规则"警告和其他),我完全困惑了关于我的警告。

所以我有一个结构:

typedef struct {
    unsigned char precision;
    unsigned char scale;
    unsigned char array[33];
} DBNUMERIC;

从MS SQL Server检索数据时,此结构体由FreeTDS库填充。我知道从array[1]开始有64位整数(以big-endian表示),我想得到它

int64_t result = 0;
result = be64toh(*((decltype(result)*)(numeric.array + 1)));

但是GCC给了我警告dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]。但如果我使用代码:

int64_t result = 0;
decltype(result)* temp_ptr = (decltype(result)*)(numeric.array + 1);
decltype(result) temp = *temp_ptr;
result = be64toh(temp);

没有关于违反严格别名规则的警告。我不认为这个代码与原来的不同,所以我很困惑。如何将数组中的8个字节转换为int64_t变量?

这两种情况都违反了严格的别名规则。gcc的严格混叠警告会受到假阴性和假阳性的影响,这取决于警告和优化级别。

如果你想以严格的别名规则不允许的方式键入pun,那么你应该只使用std::memcpy:

std::memcpy(&result, numeric.array+1, sizeof(int64_t ));

我们可以从以下来源看到;这篇文章《类型双关、严格别名和优化》以及我在回答中引用的关于类型双关和并集的std讨论告诉我们,编译器应该足够聪明,可以优化使用memcpy来生成高效的代码。