程序不应该按照“C faq”工作,但它有效

时间:2016-02-02 12:42:40

标签: c coredump

当我遇到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,因为我只是复制粘贴代码,实际上,我使用正确的方法。

2 个答案:

答案 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基本无关。您需要查看编译器的文档,了解定义的内容(如果有的话)。

很可能你的编译器根本没有定义它,在这种情况下它是未定义的,因此可能导致任何行为,包括出现工作或崩溃。