【问题标题】:How portable is code with #pragma optimize?#pragma 优化的代码的可移植性如何?
【发布时间】:2014-03-17 14:42:36
【问题描述】:

使用#pragma optimize 的代码的可移植性如何?大多数编译器是否支持它?对这个#pragma 的支持有多完善?

【问题讨论】:

  • 我可以告诉你PS3版的gcc不支持这个。
  • 你能举个例子说明你将如何在其他可移植代码中使用它吗?由于其他原因,我只见过在特定于编译器的代码中使用这种编译指示。
  • gcc 4.4+ 有#pragma GCC optimize。您通常可以假设 pragma 是不可移植的。
  • ANSI 标准中指定的“#pragma”命令具有任意实现定义的效果。在 GNU C 预处理器中,'#pragma' 首先尝试运行游戏'rogue';如果失败,它会尝试运行游戏“hack”;如果失败,它会尝试运行显示河内塔的 GNU Emacs;如果失败,它会报告一个致命错误。在任何情况下,预处理都不会继续。 -- Richard M. Stallman,GNU C 预处理器,1.34 版 ---- #pragma 完全是关于编译器定义的行为,即,非便携式。
  • @sharptooth:只有在下一次代码审查之前,他才会(希望)看到他的方式的错误,就像那个人使用#pragma once 而不是正确的标题保护一样。

标签: c++ c compiler-construction portability pragma


【解决方案1】:

#pragma 是编译器添加非认可和不可移植语言扩展*认可和可移植方式。

基本上,您永远无法确定,并且至少有一个主要的 C++ 编译器 (g++) 不支持此编译指示。


*:

来自 C++ 标准 (N3242):

16.6 Pragma 指令[cpp.pragma]

表单的预处理指令

# pragma pp-tokensopt 换行

使实现以实现定义的方式运行。该行为可能导致翻译失败或导致翻译器或生成的程序以不合格的方式运行。任何未被实现识别的编译指示都会被忽略。

来自 C 标准(委员会草案 - 2011 年 4 月 12 日):

6.10.6 Pragma 指令

语义

表单的预处理指令

# pragma pp-tokensopt 换行

预处理令牌STDC 没有立即跟在pragma 之后 指令(在任何宏替换之前)174) 导致实现在 实现定义的方式。该行为可能会导致翻译失败或导致 翻译器或生成的程序以不合格的方式运行。任何此类 实现无法识别的pragma 将被忽略。

这是一个例子:

int main () {
    #pragma omp parallel for
    for (int i=0; i<16; ++i) {}
}

C 和 C++ OpenMP API 的很大一部分实现为 #pragmas。

【讨论】:

  • C 标准 C11 6.10.6 是相同的(除了一些关于#pragma STDC 的特殊规则)。
  • @Lundin:在您发表评论前一分钟编辑;)
  • 但是我检查了实际标准,而不仅仅是草案;)但是,在这种情况下它们是相同的。
【解决方案2】:

依赖编译器标志通常不是一个好主意,因为每个编译器都有自己的行为。

不应使用此标志,因为它是您注入代码的编译级别规范。

通常和理论上,如果不使用此标志,编译器应忽略此标志。

【讨论】:

  • @DevSolar:准确。你的打字速度比我快!
【解决方案3】:

#pragma 关键字是可移植的,因为它应该始终编译,尽管在编译器上。但是,编译指示是特定于编译器的,因此在更改编译器时可能会抱怨一些警告。一些编译指示被广泛使用,例如来自 OpenMP 的编译指示。为了使代码尽可能地移植,您可以使用 #ifdef/#endif 围绕您的编译指示,这取决于您使用的编译器。例如:

#ifdef __ICC
   #pragma optimize
#endif

编译器通常会定义一些宏,例如__ICC,使代码知道正在使用哪个编译器。

【讨论】:

    【解决方案4】:

    #pragma 的任何使用都是特定于编译器的。

    For example: GNU、英特尔和 IBM:

    #warning "Do not use ABC, which is deprecated. Use XYZ instead."
    

    微软:

    #pragma message("Do not use ABC, which is deprecated. Use XYZ instead.")
    

    关于您对#pragma optimize 的具体问题,gccmicrosoft 支持,但不代表将来会。

    【讨论】:

    • 咦,#warning 是从哪里来的?与#pragma 不同,它绝对不是可移植的,因为它不是标准 C。
    • #warning 不是#pragma。所以 GCC 确实以不可移植的方式实现了他们的不可移植代码,d'oh。
    • @phresnel:它是不可移植的,因为未来的标准可能会引入与 gcc 的 #warning 含义不同的预处理器指令 #warning。并非所有编译器扩展都是编译指示,事实上大多数都不是。将扩展实现为编译指示的原因是,如果您认为不支持该扩展的编译器应该忽略它。在这种情况下,您宁愿编写用户收到警告的特定于 GCC 的代码,还是编写不知道是否会发出警告的更便携的代码?取决于警告的重要性。
    【解决方案5】:

    #pragma 不可移植,句号。有一个版本的 gcc 曾经在遇到该版本时开始游戏

    我们在工作中使用的编译器,有两个肯定不支持#pragma optimise,其他的我没法回答。

    即使他们这样做了,由于用于优化的命令行开关不同,编译指示的选项也可能不同。

    【讨论】:

    • 令牌#pragma 可移植的。接下来的不是。
    • 其他编译器不强制支持特定的#pragma,但如果编译器不能识别一个,它应该被忽略。这是 C 标准所要求的。
    • a) 这使得它非常不便携。 b) 如果它识别出之后发生了什么,但它对另一个编译器有不同的影响?那有多便携? c) 编译器可以识别 pragma 关键字并导致编译错误。这是允许的行为。
    • 这一切并没有使名为 #pragmatoken 是可移植的,即被认可的。这是一个有趣的元讨论。我真的是意思那个token,意思是preprocessing token :)