关于C#:为什么int _$[:>=<%-!.0,}; 能编译通过

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

今天我发现奇怪的语法

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

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

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

为什么它能编译?


使用有向图(见下文),该线将转换为:

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

在右边,.0double字,!是逻辑否定运算符,-是算术否定运算符,,是尾随逗号。{-!.0,}一起是数组初始值设定项。

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

C11 §6.4.6 Punctuators

In all aspects of the language, the six tokens

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

behave, respectively, the same as the six tokens

1
[  ]  {  }  #  ##


好,

  • 下划线_是允许的标识符字符,
  • 有些实施中也允许使用美元符号$
  • 左括号[表示类型应为数组,
  • :>]的有向图,
  • 等于=是赋值,
  • <%{的有向图,
  • -!.0只是-1(.0是一个双字面的0.0!含蓄地向(int) 0投射,并在逻辑上颠倒,-是负的)。
  • 数组初始值设定项1,(2,3,),
  • ;结束了声明。

所以你得到

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


如果我们替换你的代码行中的有向图:><%,我们最终会得到

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

相当于

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

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

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


这是由于C中的有向图而产生的。有问题的行按如下方式解码:

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

此外:

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