`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.
我在一个网站上看到 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.