GCC杂注在头文件中添加/删除编译器选项

ocebsuys  于 2023-10-19  发布在  其他
关注(0)|答案(3)|浏览(119)

我开发了一个跨平台的库,它在套接字通信中合理地使用了type-punning。这个库已经在许多项目中使用,其中一些我可能不知道。
不正确地使用这个库会导致危险的Undefined Behavior。我想尽我所能确保这个图书馆得到适当的使用。
当然,除了文档之外,在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

有办法吗?

pepwfjgg

pepwfjgg1#

让我们从我认为是错误的前提开始:
不正确地使用这个库会导致危险的Undefined Behavior。我想尽我所能确保这个图书馆得到适当的使用。
如果你的库以-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才能让它按预期运行,那么您可能已经在库中的其他地方使用过的代码也是如此。

6psbrbz9

6psbrbz92#

您可以尝试诊断杂注并更改警告的错误级别。更多详情请点击此处:
http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html

ecbunoof

ecbunoof3#

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

相关问题