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

时间:2013-10-17 16:03:53

标签: c++ gcc compiler-options

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

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

除了文档当然,在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

有办法吗?

3 个答案:

答案 0 :(得分:1)

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

  

错误地使用此库可能导致危险的不确定行为。我想尽我最大的能力确保该库的正确使用。

如果您的库确实以-fstrict-aliasing中断的方式键入punning,则根据C ++标准,无论传递了哪些编译器标志,它都具有未定义的行为。当使用某些标志(尤其是-fno-strict-aliasing)进行编译时,该程序似乎可以在某些编译器上运行,这一事实并不会改变这一点。

因此,最好的解决方案是按照Florian所说的做:更改代码,使其符合C ++语言规范。除非您这样做,否则您将永远处于冰薄上。

“是的,是的”,你说,“但是在那之前,我该怎么做才能缓解这个问题?”

我建议在库初始化期间使用一个run-time check,以检测已导致其行为异常的方式进行编译。例如:

// 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。

但是让我再次强调:我的代码具有 undefined 行为!有(不能)不能保证它会起作用。符合标准的C ++编译器可以将其编译为返回0,崩溃或启动Global Thermonuclear War的代码!如果您需要-fno-strict-aliasing使它按预期运行,那么对于您可能已经在库中其他地方使用的代码也是如此。

答案 1 :(得分:0)

您可以尝试使用Diagnostic pragma并更改警告的错误级别。更多细节在这里:

http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html

答案 2 :(得分:0)

如果您的库是一个仅限标题的库,我认为处理此问题的唯一方法是修复严格的别名冲突。如果在您定义的类型之间发生违规,则可以使用涉及联合的常用技巧或may_alias类型属性。如果您的库使用预定义的sockaddr类型,则可能很难。