_Pragma运算符允许在函数原型声明的中间吗?

huangapple go评论64阅读模式
英文:

Are _Pragma operators allowed in the middle of function prototype declarations?

问题

I've encountered some code like this:

void _Pragma("function") f() {
  int i = 0;
  _Pragma("loop");
  while (i < 100) {
    ...
  }
}

GCC编译这段代码时没有问题。但我不确定标准中具体允许_Pragma出现在这种位置,特别是在voidf()之间。

我的C11标准版本(N1570)中写道:

6.10.9 Pragma operator

Semantics

A unary operator expression of the form:

_Pragma ( string-literal )

...

给出的示例几乎与#pragma相同,这意味着它应该单独占据一行。

第6.5.3节 一元操作符 甚至没有提到_Pragma

在语法规则中,我找不到允许一元操作符出现在voidf()之间的位置。

GCC文档只是声称:

标准对_Pragma操作符的出现位置没有明确规定。

我认为除非明确在语法上允许,否则应该禁止在不明确规定的位置使用_Pragma。这是否未指定或由实现定义允许_Pragma出现在这些位置呢?

英文:

I've encountered some code like this:

void _Pragma(&quot;function&quot;) f() {
  int i = 0;
  _Pragma(&quot;loop&quot;);
  while (i &lt; 100) {
    ...
  }
}

GCC compiles it without issues. But I don't see exactly where in the standard it allows _Pragma's to appear in such positions, especially between the void and f().

My version of the C11 standard (N1570) states:

> 6.10.9 Pragma operator
>
> Semantics
>
> A unary operator expression of the form:
>
> _Pragma ( string-literal )
> ...

The example given behaves almost as #pragma, which means, on a line by its own.

Section 6.5.3. Unary operators does not even mention _Pragma.

I fail to see in the syntactic rules where unary operators would be allowed in the position between void and f().

The GCC docs just claim that:

> The standard is unclear on where a _Pragma operator can appear.

I would assume that it is forbidden anywhere where not syntactically explicitly allowed.

Is it unspecifed, or implementation-defined, to allow such occurrences of _Pragma?

答案1

得分: 3

_Pragma 的主要目的是允许你在预处理#define宏内部使用编译指示。对于其他目的使用它通常没有意义。

此外,6.10.9 规定:

> 生成的字符序列经过第三个转换阶段处理,生成处理预处理令牌,它们被执行,就好像它们是#pragma指令中的pp-token。

你可以解释为:应该单独写在一行上,因为#pragma - 作为预处理指令 - 就是这样工作的。在这种情况下,因为诸如void #pragma function这样的代码是无效的,对于_Pragma来说也是一样的。

引用你找到的gcc文档:
> 为了安全起见,最好将其放在除了#define之外的指令之外,并将其放在独立的一行上。

此外,一般的最佳实践是:

  • 不要随意编写奇怪的代码。
  • 不要仅仅为了某种目的而使用奇怪的编译器扩展。

尽管编译器应该忽略未识别的编译指示,这似乎是gcc、clang等编译器正在做的。如果你使用严格的设置编译(-std=c17 -pedantic -Wall -Wextra),它们会发出警告然后忽略它。

英文:

_Pragma pretty much have one single purpose: to allow you to use pragmas inside pre-processor #define macros. It isn't (shouldn't be) meaningful to use it for any other purpose.

Other than that, 6.10.9 says:

> The resulting sequence of characters is processed through translation phase 3 to produce preprocessing tokens that are executed as if they were the pp-tokens in a pragma directive.

You could interpret this as: meant to be written on a line of its own, since #pragma - being a pre-processor directive - works that way. In that case, since code such as void #pragma function is invalid, the same should go for _Pragma.

To quote the gcc doc you found:
> To be safe, you are probably best keeping it out of directives other than #define, and putting it on a line of its own.

In addition, general best practices are:

  • Don't write strange code just for the heck of it.
  • Don't use weird compiler extensions just for the heck of it.

Although compilers should ignore unrecognized pragmas and that seems to be what gcc, clang et al are doing. Neither "compiles it without any issues" if you compile with strict settings -std=c17 -pedantic -Wall -Wextra, they warn and then ignore it.

huangapple
  • 本文由 发表于 2023年6月9日 14:45:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76437839.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定