让我们从我认为是错误的前提开始:
错误地使用这个库会导致危险的未定义行为。我想尽我所能确保这个库被正确使用。
如果您的库确实以中断的方式进行类型双关语,那么无论传递了哪些编译器标志-fstrict-aliasing
,它都会根据 C++ 标准具有未定义的行为。当使用某些标志(特别是 )编译时,该程序似乎可以在某些编译器上运行这一事实并没有改变这一点。-fno-strict-aliasing
因此,最好的解决方案就是按照 Florian 所说的去做:更改代码,使其符合 C++ 语言规范。除非你这样做,否则你永远如履薄冰。
“是的,是的”,你说,“但在那之前,我能做些什么来缓解这个问题?”
我建议包括在库初始化期间使用的运行时检查,以检测是否以一种会导致其行为异常的方式编译的情况。例如:
// Given two pointers to the *same* address, return 1 if the compiler
// is behaving as if -fstrict-aliasing is specified, and 0 if not.
//
// Based on https://blog.regehr.org/archives/959 .
static int sae_helper(int *h, long *k)
{
// Write a 1.
*h = 1;
// Overwrite it with all zeroes using a pointer with a different type.
// With naive semantics, '*h' is now 0. But when -fstrict-aliasing is
// enabled, the compiler will think 'h' and 'k' point to different
// memory locations ...
*k = 0;
// ... and therefore will optimize this read as 1.
return *h;
}
int strict_aliasing_enabled()
{
long k = 0;
// Undefined behavior! But we're only doing this because other
// code in the library also has undefined behavior, and we want
// to predict how that code will behave.
return sae_helper((int*)&k, &k);
}
(以上是 C 而不是 C++,只是为了便于在两种语言中使用。)
现在在您的初始化例程中,调用strict_aliasing_enabled()
,如果它返回 1,则立即退出并显示错误消息,说明库编译不正确。这将有助于保护最终用户免受不当行为的影响,并提醒客户端程序的开发人员他们需要修复其构建。
我已经用 gcc-5.4.0 和 clang-8.0.1 测试了这段代码。-O2
传递时,返回strict_aliasing_enabled()
1。-O2 -fno-strict-aliasing
传递时,该函数返回 0。
但是让我再次强调一下:我的代码有未定义的行为!(可以)不能保证它会起作用。符合标准的 C++ 编译器可以将其编译为返回 0、崩溃或引发全球热核战争的代码!-fno-strict-aliasing
如果您需要它按预期运行,那么您可能已经在库中其他地方使用的代码也是如此。