当我遇到this页面时,我刚刚浏览了c-faq
。我说以下程序将有一个核心转储:
struct list {
char *item;
struct list *next;
}
/* Here is the main program. */
main(argc, argv)
{}
他们告诉核心转储发生的原因是:
结构声明结尾处缺少分号会导致main被声明为返回结构。 (由于介入的注释,很难看到连接。)由于结构值函数通常是通过添加隐藏的返回指针来实现的(参见问题2.9),因此生成的main()代码尝试接受三个参数,尽管只有两个传递(在这种情况下,通过C启动代码)。另见问题10.9和16.4。
虽然,当我通过here在线运行这个程序时,它运行得很好,程序确实运行到最后。另外,当我使用gcc编译这个程序时,我没有收到任何警告。
我感到很惊讶,因为程序应该没有运行到最后。有人能告诉我为什么这个程序有效吗?如果它是正确的,为什么提到该程序将无法工作(任何可能崩溃的机会?)。
注意:请不要发表评论,例如使用int main
,因为我只是复制粘贴代码,实际上,我使用正确的方法。
答案 0 :(得分:9)
这是对C FAQ的误读。
C FAQ解释了代码错误的原因,但并未说明代码是否会崩溃。以下是您引用的部分内容:
由于结构值函数通常通过添加隐藏的返回指针实现 ...
我更加强调。 C FAQ解释了代码可能崩溃的原因。两种情况下代码都不正确。 (理论上,行为可能是实现定义的,但是你的C实现极不可能定义在这种情况下会发生什么。)
在许多系统(ABI)上,如果结构足够小,返回结构的函数将使用寄存器作为返回值。我不知道普通x64 ABI的限制是什么,但是两个单词(两个指针)相当小。
答案 1 :(得分:1)
根据标准,该程序似乎不违法。 让我们先看一下清理过的程序:
struct list {
char *item;
struct list *next;
} main(argc, argv){}
好的,所以我们将main声明为返回结构列表。 现在让我们看看根据ISO 9899:2011的main的有效声明 (C11)虽然C99基本相同。
应使用返回类型int定义并且不带参数 或者有两个参数(这里称为argc和argv,尽管是任何参数) 可以使用名称,因为它们是它们所在的函数的本地名称 声明)。或者以其他一些实现定义的方式。
(略有删节) 在我看来,这因此完全属于"其他一些实现定义的方式的第三个定义"意味着它处于实现定义行为的领域。
因此,这根本不是C的问题,而是由使用中的编译器决定,因此与C faq基本无关。您需要查看编译器的文档,了解定义的内容(如果有的话)。
很可能你的编译器根本没有定义它,在这种情况下它是未定义的,因此可能导致任何行为,包括出现工作或崩溃。