`int main(int argc, char* argv<::>)` 如何成为 main 的有效签名?

How is `int main(int argc, char* argv<::>)` a valid signature of main?

我在一个网站上看到 int main(int argc, char* argv<::>) 也可以用作 main 的签名。令人惊讶的是,以下程序:

int main(int argc, char* argv<::>)
{
  return 0;
}

编译时会发出 GCC 中的任何警告以及 clang。它还在 C++ 中编译。

那么,int main(int argc, char* argv<::>) 是如何成为 main 的有效签名的呢?

<::>二合字母;它们分别相当于 []

我相信它们在现实生活中的唯一用途是创建混淆代码,例如您提供的代码,但它们是 C99 标准的一部分,旨在取代更笨拙的 trigraphs 几乎永远都在 C 语言中。

最初的目的是帮助程序员处理缺少某些标点符号的国家字符集。由于现在很少遇到不支持(至少)八位字符集的环境,允许像 Ä 这样的字符与 [ 共存,所以这个问题基本上没有实际意义。但向后兼容性仍然被认为是必要的。

char* argv<::> 等同于 char* argv[]。这里使用的<::>是二合字母。

C11:6.4.6(第 3 页):

In all aspects of the language, the six tokens79)

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

behave, respectively, the same as the six tokens

[ ] { } # ##

except for their spelling. 80)


脚注:
79) 这些标记有时被称为“二合字母”。
80) 因此 [<: 在“字符串化”时表现不同(见 6.10.3.2),但是 可以自由互换 .

一个例子:

%: define  stringize(a) printf("Digraph \"%s\" retains its spelling in case of stringization.\n", %:a)    

调用上面的宏

stringize( %:);  

将打印

Digraph "%:" retains its spelling in case of stringization.