取消引用类型双关指针将打破严格的别名规则:字节数组到数字

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

我已经阅读了很多关于此警告的问题(Dereferencing type-punned pointer will break strict-aliasing rules, Dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing], What is the strict aliasing rule?, "dereferencing type-punned pointer will break strict-aliasing rules" warning 和其他问题)并且对我的警告感到非常困惑。

所以我有一个结构:

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

从 MS SQL 服务器检索数据时,此结构由 FreeTDS 库填充。我知道从 array[1] 开始有 64 位整数(大端),我想得到它。我使用以下代码:

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 变量?

根据警告和优化级别,您的两种情况都违反了strict aliasing rules. gcc's strict-aliasing warnings are subject to false negatives and false positives

如果您想以严格的别名规则不允许的方式输入双关语,那么您应该只使用 std::memcpy:

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

我们可以从以下来源看出;这篇文章 Type Punning, Strict Aliasing, and Optimization and the std-dicussion conversation on type punning and unions I quote in my answer here 告诉我们编译器应该足够聪明,可以针对 memcpy 的使用进行优化以生成高效的代码。