如何判断类型双关在我的平台上是否正常?

How to tell if type punning is ok on my platform?

我有一堆代码从网络中获取二进制 blob。在知道 blob 的类型后,我到目前为止使用了类型双关(伪):

uint8_t* data = network.get();
if(type == "A") {
  uint32_t* var = reinterpret_cast<uint32_t*>(data);
  ...
} else if (type == "B") {
  float* var = reinterpret_cast<float*>(data);
  ...
}

有些地方还有工会:

union A {
  float valf;
  uint32_t valu;
};

这似乎工作正常,但现在我阅读了关于类型双关的帖子,就像这是按照标准的 UB,我应该改用 memcpy。然而,事实证明它可以在许多平台上运行。

问题 1:有没有办法测试是否支持类型双关以及在我的平台上是否按预期运行?

问题 2:我能否期望主流编译器(MSVC、GCC)在我的平台上对非法类型双关发出警告或错误?

Q2: Can I expect mainstream compilers (MSVC, GCC) to warn or error on illegal type punning on my platform?

并非总是如此,即使您启用所有警告并使用静态分析(例如 recent GCC or Clang or Frama-C). See Rice's theorem.

,您也会得到误报

您可以自己编写 GCC plugin to validate your project's coding rules (perhaps inspired by these)。

draft report 提供了更多详细信息和参考。

实际上,你无法避免code reviews by senior developers (perhaps external to your team). Be aware of the Joel Test: 12 Steps to Better Code. In your software development projects, do budget some code review efforts. Read The Mythical Man-Month本书。

Q1: Is there a way to test if type punning is supported and behaves as expected on my platform?

是的,阅读编译器手册。通常有一章是关于非标准扩展的。例如 gcc C extensions or gcc C++ extensions。如果没有记录在案的非标准扩展(或者如果您为严格遵守标准而编译),您必须假设使用此类代码是不安全和未定义的行为。

gcc 传统上因在严格的指针别名违规时调用未定义的行为而臭名昭著。您可以使用 -f-no-strict-aliasing.

阻止它在优化期间利用该 UB

通过联合进行类型双关在 C 中定义明确,但在 C++ 中未定义。

Q2: Can I expect mainstream compilers (MSVC, GCC) to warn or error on illegal type punning on my platform?

不,这是非常罕见的。通常,您不能期望在调用未定义行为时会收到诊断消息。这就是静态分析工具仍然有市场的原因。此外,许多形式的未定义行为会在 运行 时间内发生。