GCC编译指示在源文件中添加/删除编译器选项

Joh*_*ing 11 c++ gcc compiler-options

我开发了一个跨平台的库,可以在套接字通信中合理使用类型.该库已经在许多项目中使用,其中一些我可能不知道.

错误地使用此库可能会导致危险的未定义行为.我想尽我所能确保正确使用这个库.

除了文档当然,在G ++下,我知道要做的最好的方法是使用-fstrict_aliasing-Wstrict-aliasing选项.

GCC下是否有办法在源文件级别应用这些选项?

换句话说,我想写下面的内容:

MyFancyLib.h

#ifndef MY_FANCY_LIB_H
#define MY_FANCY_LIB_H

#pragma (something that pushes the current compiler options)
#pragma (something to set -fstrict_aliasing and -Wstrict-aliasing)

// ... my stuff ...

#pragma (something to pop the compiler options)

#endif
Run Code Online (Sandbox Code Playgroud)

有办法吗?

Sco*_*eak 0

让我们从我认为错误的前提开始:

错误地使用此库可能会导致危险的未定义行为。我想尽我所能确保这个库得到正确使用。

如果您的库以破坏的方式进行类型双关,那么无论传递什么编译器标志,-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);
}
Run Code Online (Sandbox Code Playgroud)

(上面是 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如果您需要它按预期运行,那么您可能已经在库中其他地方使用的代码也是如此。