-Werror=C 中的严格别名错误
Posted
技术标签:
【中文标题】-Werror=C 中的严格别名错误【英文标题】:-Werror=strict-aliasing error in C 【发布时间】:2018-03-06 19:12:32 【问题描述】:我正在尝试调用这个函数
static inline void insert(Buffer *buf, double f, size_t index)
insert_64(buf, *(uint64_t *)&f, index);
但是,我收到了这个错误:
error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
不知道我哪里错了。
【问题讨论】:
*(uint64_t *)&f
那里。你不能假装指向float
的指针是指向uint64_t
的指针并侥幸逃脱。
Fix for dereferencing type-punned pointer will break strict-aliasing的可能重复
@LeeDanielCrocker 取消引用新指针是 UB,OP 肯定做错了什么。
看这里:What is the strict aliasing rule?
不,这不仅仅是关于便携性。打破严格的别名规则以及一些优化可能会导致更有趣的东西。看这里:blog.qt.io/blog/2011/06/10/type-punning-and-strict-aliasing
【参考方案1】:
不知道我哪里错了。
*(uint64_t *)&f
打破了严格的别名规则。见Fix for dereferencing type-punned pointer will break strict-aliasing
要修复,请使用memcpy()
以及@dbush 或union
的回答。 union
处理严格的别名规则。
void insert2(Buffer *buf, double f, size_t index)
union
double d;
uint64_t u64;
u = f ;
insert_64(buf, u.u64, index);
或者也使用一个复合文字(从C99开始可用)
void insert3(Buffer *buf, double f, size_t index)
// v-----------------------------------------v compound literal
insert_64(buf, (union double d; uint64_t u64; ).d = f.u64, index);
对于 C11,我将添加以下内容以供将来评估正确性。
_Static_assert(sizeof (double) == sizeof (uint64_t), "Unexpected sizes");
注意:稀有平台的每个整数和 FP 类型都有不同的 endian。
【讨论】:
【参考方案2】:正如 cmets 中提到的,尝试将指向一种类型的指针转换为另一种类型的指针会破坏严格的别名规则。您可以通过使用memcpy
将字节从一种类型复制到另一种类型来解决此问题:
uint64_t x;
memcpy(&x, &f, sizeof(f));
注意x
包含的内容取决于实现,即double
的表示形式是什么,是系统大端还是小端,是double
64 位等。
【讨论】:
以上是关于-Werror=C 中的严格别名错误的主要内容,如果未能解决你的问题,请参考以下文章