I saw CodeGolf 上的一段代码 https://codegolf.stackexchange.com/a/69193/13441这是一个编译器炸弹,其中main
被声明为一个巨大的数组。我尝试了以下(非炸弹)版本:
int main[1] = { 0 };
它似乎在 Clang 下编译得很好,在 GCC 下只有一个警告:
警告:“main”通常是一个函数 [-Wmain]
当然,生成的二进制文件是垃圾。
但为什么它能编译呢? C 规范是否允许这样做?我认为相关的部分说:
5.1.2.2.1 程序启动
程序启动时调用的函数名为 main。该实现没有声明该函数的原型。它应使用 int 返回类型进行定义,并且不带参数 [...] 或带两个参数 [...] 或以某种其他实现定义的方式定义。
“其他一些实现定义的方式”是否包括全局数组? (在我看来,该规范仍然指的是function.)
如果不是,它是编译器扩展吗?或者工具链的一个功能,用于其他目的,并且他们决定通过前端提供它?
这是因为 C 允许“非托管”或独立环境,不需要main
功能。这意味着这个名字main
被释放用于其他用途。这就是为什么语言本身允许这样的声明。大多数编译器都被设计为支持两者(区别主要在于链接的完成方式),因此它们不会禁止在托管环境中非法的构造。
您在标准中引用的部分是指托管环境,独立式的对应部分是:
在独立环境中(其中 C 程序执行可以在没有任何
操作系统的好处),程序中调用的函数的名称和类型
启动是实现定义的。任何可供独立使用的图书馆设施
除了第 4 条要求的最小集合之外,程序都是实现定义的。
如果您像往常一样链接它,它将变得很糟糕,因为链接器通常对符号的性质知之甚少(它具有什么类型,甚至它是一个函数或变量)。在这种情况下,链接器将愉快地解析对main
到名为的变量main
。如果未找到该符号,将导致链接错误。
如果您像往常一样链接它,您基本上是在尝试在托管操作中使用编译器,然后不定义main
正如您所期望的那样,按照附录 J.2 意味着未定义的行为:
在以下情况下,该行为是未定义的:
- ...
- 托管环境中的程序未定义名为的函数
主要的
使用一个
指明表格(5.1.2.2.1)
独立可能性的目的是能够在未给出标准库或 CRT 初始化的环境中使用 C。这意味着之前运行的代码main
被调用(即初始化 C 运行时的 CRT 初始化)可能不会提供,并且您需要自己提供(并且您可能决定拥有一个main
或者可能决定不这样做)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)