“ int main;”是一个有效的 C/C + + 程序吗?

我这么问是因为我的编译器似乎是这么认为的,尽管我并不这么认为。

echo 'int main;' | cc -x c - -Wall
echo 'int main;' | c++ -x c++ - -Wall

Clang issues no warning or error with this, and gcc issues only the meek warning: 'main' is usually a function [-Wmain], but only when compiled as C. Specifying a -std= doesn’t seem to matter.

否则,它可以很好地编译和链接,但是在执行时,它会立即以 SIGBUS结束(对我来说)。

Reading through the (excellent) answers at Main ()在 C 和 C + + 中应该返回什么? and a quick grep through the language specs, it would certainly 看起来 to me that a main 功能 is required. But the verbiage from gcc’s -Wmain (‘main’ is 通常 a function) (and the dearth of errors here) seems to possibly suggest otherwise.

但是为什么呢? 是否有一些奇怪的边缘情况或“历史”用于这个? 有人知道什么给?

我的观点,我想,是我真的认为这应该是一个在托管环境中的 错误,嗯?

11162 次浏览

main不是 保留意见,它只是一个 预定义标识符(像 cinendlnpos...) ,所以你可以声明一个名为 main的变量,初始化它,然后打印出它的值。

当然:

  • the warning is useful since this is quite error prone;
  • 您可以拥有一个没有 main()函数(库)的源文件。

剪辑

参考资料:

由于这个问题被双重标记为 C 和 C + + ,因此 C + + 和 C 的推理会有所不同:

  • C + + 使用名称错位来帮助链接器区分不同类型的文本相同的符号,例如全局变量 xyz和独立的全局函数 xyz(int)。然而,main这个名字从来没有被破坏过。
  • C 语言不使用损坏,因此程序可以通过提供一种符号代替不同的符号来混淆链接器,并使程序成功地进行链接。

这就是这里发生的事情: 链接器期望找到符号 main,而它确实找到了。它把这个符号当作一个函数来“连接”,因为它不知道更好的是什么。运行时库中将控制传递给 main的部分要求链接器提供 main,因此链接器给出符号 main,让链接阶段完成。当然,这在运行时会失败,因为 main不是一个函数。

下面是同一问题的另一个例子:

文件 x.c:

#include <stdio.h>
int foo(); // <<== main() expects this
int main(){
printf("%p\n", (void*)&foo);
return 0;
}

文件 y.c:

int foo; // <<== external definition supplies a symbol of a wrong kind

编译:

gcc x.c y.c

这样编译,它可能会运行,但它是未定义行为的,因为向编译器承诺的符号类型与向链接器提供的实际符号不同。

至于这个警告,我认为它是合理的: C 允许您构建没有 main函数的库,所以如果出于某种未知的原因需要定义一个变量 main,编译器会释放 main的名称以供其他使用。

这是一个警告,因为它在技术上并不是不允许的。启动代码将使用“ main”的符号位置,并使用三个标准参数(argc、 argv 和 envp)跳转到它。它没有,并且在链接时不能检查它是否实际上是一个函数,甚至不能检查它是否有那些参数。这也是 int main (int argc,char * * argv)可以工作的原因——编译器不知道 envp 参数,它只是碰巧没有被使用,它是调用者清除。

开个玩笑,你可以这么做

int main = 0xCBCBCBCB;

on an x86 machine and, ignoring warnings and similar stuff, it will not just compile but actually work too.

有人使用类似的技术编写了一个可直接在多个体系结构上运行的可执行文件(排序)-http://phrack.org/issues/57/17.html#article。它也被用来赢得 IOCCC-http://www.ioccc.org/1984/mullender/mullender.c

这是一个有效的程序吗?

没有。

它不是一个程序,因为它没有可执行的部分。

Is it valid to compile?

是的。

它可以与有效的程序一起使用吗?

是的。

并非所有编译的代码都必须是可执行的才有效。

You have effectively built an object file. It is not a valid executable, however another program could link to the object main in the resultant file by loading it at runtime.

Should this be an error?

Traditionally, C++ allows the user to do things that may be seem like they have no valid use but that fit with the syntax of the language.

我的意思是,当然,这可以被重新归类为一个错误,但是为什么呢?这样做的目的是什么?

只要这个功能在实际代码中使用的理论可能性存在,那么根据语言,使用一个名为 main的非函数对象就不太可能导致错误。

int main;是一个有效的 C/C + + 程序吗?

C/C + + 程序是什么并不完全清楚。

int main;是一个有效的 C 程序吗?

是的。允许独立的实现接受这样的程序。main在一个独立的环境中没有任何特殊的意义。

It is 没有 valid in a hosted environment.

int main;是一个有效的 C + + 程序吗?

彼此彼此。

为什么会崩溃?

程序在 你的环境中没有意义。在独立环境中,程序的启动和终止以及 main的含义都是实现定义的。

为什么编译器要警告我?

只要编译器不拒绝符合要求的程序,它可能会对您发出任何它喜欢的警告。另一方面,警告是诊断不一致程序所需的全部。由于这个翻译单元不能作为有效宿主程序的一部分,因此诊断消息是合理的。

Is gcc a freestanding environment, or is it a hosted environment?

是的。

gcc记录了 -ffreestanding编译标志。加上它,警告就消失了。你可以在构建内核或固件时使用它。

g++没有记录这样的标志。提供它似乎对这个计划没有任何影响。假设 g + + 提供的环境是托管的,这可能是安全的。在这种情况下缺乏诊断是一个错误。

我的观点是,我真的认为这应该是托管环境中的一个错误,对吗?

错在你。您没有指定返回 int的名为 main的函数,并试图在宿主环境中使用您的程序。

假设您有一个编译单元,它定义了一个名为 main的全局变量。这在独立环境中很可能是合法的,因为构成程序的内容取决于独立环境中的实现。

假设您有另一个编译单元,它定义了一个名为 main的全局函数,该函数返回一个 int并且不接受任何参数。这正是托管环境中的程序所需要的。

如果只在独立环境中使用第一个编译单元,而在托管环境中使用第二个编译单元,那么一切都很好。如果在一个程序中同时使用这两种方法会怎样?在 C + + 中,您违反了一个定义规则。这是未定义行为。在 c 语言中,你违反了一条规则,即所有对单个符号的引用都必须是一致的,否则就是未定义行为。未定义行为就是“出狱,自由!”向开发人员提供一个实现的卡。实现对未定义行为的任何响应都符合标准。实现不需要警告未定义行为,更不用说检测了。

如果您只使用了其中的一个编译单元,但是使用了错误的单元(这正是您所做的) ,该怎么办?在 C 中,情况是明确的。未能在托管环境中以两种标准形式之一定义函数 main是未定义行为。假设您根本没有定义 main。编译器/链接器不必说明这个错误。他们确实抱怨,这是对他们的尊重。编译和链接的 C 程序没有错误是你的错,不是编译器的错。

在 C + + 中这一点就不那么清楚了,因为在宿主环境中未能定义函数 abc0是一个错误,而不是未定义行为(换句话说,它必须被诊断)。然而,C + + 中的一个定义规则意味着链接器可能相当笨。链接器的工作是解析外部引用,并且由于一个定义规则,链接器不必知道这些符号的含义。您提供了一个名为 main的符号,链接器期望看到一个名为 main的符号,所以就链接器而言,一切都很好。

I would like to add to the answers already given by citing the actual language standards.

Is ‘int main;’ a valid C program?

简短的回答(我的观点) : 只有在您的实现使用“独立执行环境”的情况下。

以下引用自 C11

5. Environment

An implementation translates C source files and executes C 程序 in 两个数据处理系统环境,称为 翻译环境和执行环境[ ... ]

5.1.2执行环境

定义了两个执行环境: 独立的和托管的 在这两种情况下,当指定的 C 函数为 由执行环境调用。

5.1.2.1独立环境

在一个独立的环境中(在这种环境中,C 程序的执行可能需要 名称和类型 of the function called at program startup are implementation-defined.

5.1.2.2宿主环境

托管环境不需要提供,但应符合 如有下列规格。

5.1.2.2.1程序启动

在程序启动时调用的函数名为 总台 被定义为返回类型为 int 且没有参数[ ... ]或 有两个参数[ ... ]或等价或在其他 实现定义的方式。

由此可见:

  • A C11 program can have a freestanding or a hosted execution environment and be valid.
  • 如果它有一个独立的,不需要存在一个主要的功能。
  • 否则,必须有一个返回值类型为 Int的值。

在独立执行环境中,我认为这是一个不允许启动的有效程序,因为没有5.1.2中要求的函数。 在宿主执行环境中,虽然代码引入了一个名为 总台的对象,但是它不能提供返回值,所以我认为从这个意义上来说,它不是一个有效的程序,尽管人们也可以像之前一样认为,如果程序不应该被执行(例如,on 可能只想提供数据) ,那么它就不允许这样做。

“ int main;”是一个有效的 C + + 程序吗?

简短的回答(我的观点) : 只有在您的实现使用“独立执行环境”的情况下。

引自 C + + 14

3.6.1主要功能

程序应该包含一个名为 main 的全局函数,它是 程序的指定开始。它是实现定义的是否 独立环境中的程序需要定义一个主程序 function. [...] It shall have a return type of type int, but otherwise 它的类型是实现定义的[ ... ] 别的地方。

Here, as opposed to the C11 standard, less restrictions apply to the freestanding execution environment, as no startup function is mentioned at all, while for a hosted execution environment, the case is pretty much the same as for C11.

同样,我认为对于托管的情况,您的代码不是一个有效的 C + + 14程序,但是我确信它对于独立的情况是有效的。

因为我的答案只考虑了 execution环境,所以我认为 dasblinkenlicht 的答案会起作用,因为在 翻译环境中发生的名称错误会提前发生。在这里,我不确定上面的引语是否被严格遵守。

到目前为止,对于 C 来说,它是实现定义的行为。

正如 ISO/IEC9899所说:

5.1.2.2.1 Program startup

1在程序启动时调用的函数名为 main。实现声明 no 这个函数的原型。它应该定义为一个返回类型的 int 和没有 参数:

int main(void) { /* ... */ }

或者带有两个参数(这里称为 argc 和 argv,不过任何名称都可以是 使用,因为它们在声明它们的函数中是局部的) :

int main(int argc, char *argv[]) { /* ... */ }

或等价物; 或以其他实现定义的方式。

No, this is not a valid program.

For C++ this was recently explicitly made ill-formed by 1886缺陷报告: main ()的语言链接 which says:

对于给予 main ()显式的语言链接似乎没有任何限制,但是它可能应该是格式不正确或者有条件支持的。

决议的部分内容包括以下改动:

在全局范围内声明变量 main 或使用 C 语言链接(在任何命名空间中)声明名称 main 的程序是格式不正确的。

我们可以在最新的 C++ draft standard N4527(C + + 1z 草案)中找到这样的措辞。

Clang 和 gcc 的最新版本现在使这成为一个错误(原文地址: http://melpon.org/wandbox/permlink/yzSaIOZ41lZCgcxt) :

error: main cannot be declared as global variable
int main;
^

Before this defect report, it was undefined behavior which does not require a diagnostic. On the other hand ill-formed code requires a diagnostic, the compiler can either make this a warning or an error.