为什么可以 int _$[:>=<%-!.0,};编译?

Why can int _$[:>=<%-!.0,}; compile?

今天我发现了奇怪的语法

 int _$[:>=<%-!.0,};

在一些旧代码中,但实际上代码没有注释。这行似乎没有编译错误的报告。我单独测试过,也可以编译:

int main(){
    int _$[:>=<%-!.0,};
    return 0;
}

为什么可以编译?

Digraph(见下文),该行被转换为:

int _$[]={-!.0,};

右边,.0double字面量,!是逻辑取反运算符,-是算术取反运算符,, 是结尾的逗号。 {-!.0,} 一起是一个数组初始值设定项。

左侧 int _$[] 定义了一个 int 数组。然而,还有最后一个问题,_$ 不是标准 C 中的有效标识符。一些编译器(例如,gcc)支持它作为扩展。


C11 §6.4.6 Punctuators

In all aspects of the language, the six tokens

<: :> <% %> %: %:%:

behave, respectively, the same as the six tokens

[  ]  {  }  #  ##

这是由于 digraphs 在 C 中的作用。有问题的行解码如下:

int _$ [ :> = <% - ! .0  , } ;
int _$ [ ]  = {  - ! 0.0 , } ;

此外:

  • .0double 文字。
  • ! 是布尔否定运算符,因此 !.0 产生 (int) 1.
  • - 是一元否定运算符,它产生 (int) -1.
  • 数组元素后的尾随逗号是合法的。

如果我们替换您代码行中的二合字母 :><%,我们最终会得到

int _$[]={-!.0,};

相当于

int _$[] = { -1, };

它是 int [1] 类型数组 _$ 的声明,带有初始值设定项。

请注意,这不能完全保证编译,因为标准 C 语言不会立即提供对标识符中 $ 字符的支持。它允许实现扩展支持的字符集。显然你使用的编译器在标识符中支持 $

嗯,

  • 下划线 _ 是允许的标识符字符,
  • 美元符号$ is allowed in some implementations too,
  • 左括号[表示类型应该是数组,
  • :>],
  • 的二合字母
  • 等于=是赋值,
  • <%{,
  • 的二合字母
  • -!.0 只是 -1(.0 是双重文字 0.0! 隐式转换为 (int) 0 并在逻辑上反转它,并且 -为负),
  • 您可以在数组初始值设定项 {1, (2, 3,)},
  • 中添加尾随逗号
  • ; 结束语句。,

所以你得到

int _$[] = {-1,};