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

vqlkdk9b  于 2022-11-12  发布在  其他
关注(0)|答案(4)|浏览(170)

我已经开发了一个跨平台的库,它在套接字通信中合理地使用了type-punning。这个库已经在许多项目中使用了,其中一些我可能还不知道。
不正确地使用此库可能导致危险的未定义行为。我希望尽我所能确保此库被正确使用。
当然,除了文档之外,在G++下,我所知道的最好的方法是使用-fstrict_aliasing-Wstrict-aliasing选项。
在GCC下是否有方法在源文件级别应用这些选项?
换句话说,我想写类似下面的内容:

我的奇幻书库. 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

有办法吗?

wydwbb8l

wydwbb8l1#

让我们从一个我认为是错误的前提开始:
不正确地使用此库可能导致危险的未定义行为。我希望尽我所能确保此库被正确使用。
如果您的库以-fstrict-aliasing中断的方式进行类型双关,则根据C标准 *,无论传递了什么编译器标志 *,它都具有未定义的行为。当使用某些标志(特别是-fno-strict-aliasing)编译时,程序似乎可以在某些编译器上工作,这一事实并没有改变这一点。
因此,最好的解决办法就是按照弗洛里安所说的去做:修改代码使其符合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);
}

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

llew8vvj

llew8vvj2#

您可以尝试诊断pragma并更改警告的错误级别。此处提供了更多详细信息:
http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html

wmtdaxz3

wmtdaxz33#

如果你的库是一个只有头文件的库,我认为唯一的解决方法就是修复严格的别名冲突。如果冲突发生在你定义的类型之间,你可以使用通常的技巧,包括联合,或者may_alias类型属性。如果你的库使用预定义的sockaddr类型,这可能会很困难。

x33g5p2x

x33g5p2x4#

我不喜欢反对者。你可以在这个页面上看到一个很好的帖子:https://www.codingame.com/playgrounds/58302/using-pragma-for-compile-optimization
所有其他答案显然与问题无关,因此以下是GCC的实际文档:
https://gcc.gnu.org/onlinedocs/gcc/Pragmas.html
其他编译器将有自己的方法,因此您将需要查找这些方法并创建一些宏来处理此问题。
祝你好运。很抱歉你花了10年才得到任何相关的答案。

相关问题