【问题标题】:Why it is allowed to declare a C function no return type specfied?为什么允许声明一个没有指定返回类型的 C 函数?
【发布时间】:2015-09-28 07:05:48
【问题描述】:

我惊讶地发现这是一个有效的 C 函数声明:

f() {
    return 10; 
}

未指定函数的返回类型。它不仅编译,而且实际上返回 10。

void main() {
        int i = f();
        printf("i = %d\n", i); 
}

此代码产生以下输出:

i = 10

这是用 gcc 4.8.4 编译的。 为什么没有明确指定返回类型的函数声明编译时没有错误/警告?

编辑:正如here 解释的那样,返回类型不是函数签名的一部分,您不能基于不同的返回类型重载函数,但这并不能回答问题是需要返回类型用于函数声明。

【问题讨论】:

  • C 用于允许隐式 int 返回类型
  • 因为支持 implicit int 以防止破坏旧代码,即使 C99 放弃了它。
  • 请将void main() 更改为int main()。您不返回值,但main() 是编译器将为您提供return 0 的唯一函数。
  • 在准标准 C 和 C89/90 中有效。在旧标准 (C99) 或当前标准 (C11) 中无效。出于向后兼容性的原因,编译器继续支持它,但GCC 5.1.0 已将默认编译模式 C11 与 GNU 扩展 (-std=gnu11) 替换为 C90,因此f 等定义默认情况下至少会生成警告.
  • 有关main() 函数的讨论(扩展),请参阅What should main() return in C and C++

标签: c function


【解决方案1】:

在 ANSI C (C89/90) 中,未指定的返回类型隐含为 int。自 C99 以来,这已被正式禁止,但这并不能阻止编译器实现它。如果在 C99 或 C11 模式下编译,GCC 的 -pedantic 或类似的标志应该会发出警告。

编辑:在 GCC 4.9 中,-Wall 在默认 (GNU C) 模式下警告它,-pedantic-std=c99 警告它。

【讨论】:

  • 术语“ANSI C”通常但不正确地用来指代 1989 年标准定义的语言。 ANSI(美国国家标准协会)在发布时采用了 ISO C 标准的每个版本;它目前识别 C11,并且仅识别 C11。我建议改为“ISO C90”。
  • C89 是 ANSI 标准; ISO C90 是不久之后取代 C89 的通用标准,甚至在美国也是如此。 GCC -ansi 标志表示-std=c89(又名-std=c90)。
  • 我承认这是模棱两可的,但 incorrect 绝对是主观的;从 Wikipedia 到编译器文档,术语“ANSI C”随处可见,指的是 C89/C90。鉴于 ANSI 从未将这种语言称为“C”以外的任何东西,或者以其他方式将其后来的标准与 ISO 的标准区分开来,因此说“ANSI C”正确地指代最新批准的标准可能更不正确现有文档几乎专门使用它来引用原始的 1989 ANSI 和 1990 ISO 标准。
【解决方案2】:

现代 C 中它不是一个有效的函数声明(它是在“经典”C89/90 版本的语言中)。您的编译器接受它的事实并不意味着它是有效的。这只是意味着您的编译器没有配置为严格执行标准 C 语言的现代要求。

后者也很明显,它允许您使用 void 返回类型声明 main

如果您想使用 GCC 来验证代码的形式有效性,您需要在命令行中指定 -std=...-pedantic-errors 开关。它不会使它万无一失,但它会使其更加合规。

附:默认情况下,即使在 C++ 代码中,GCC 也会允许您这样做。而且它在 C++ 中从未合法。

【讨论】:

  • 定义void main()不是违反约束;不需要诊断。但它具有未定义的行为除非实现将其记录为允许的形式。 不要那样做。
  • 因此,GCC 有权投诉 void main(),因为它没有将其记录为允许的形式。
【解决方案3】:

fmain 的函数声明都不符合 C 标准。现代 C 编译器会发出诊断消息。

之前,在采用C99标准之前,如果没有指定函数返回类型,则假定为int

某些编译器,例如 MS VC++,允许将函数 main 声明为返回类型为 void;但是,根据 C 标准(和 C++ 标准),函数 main 的返回类型应为 int

在 C 函数中 main 应声明为(如果它没有参数)

int main( void )

【讨论】:

  • 请注意,C 确实允许“或以其他一些实现定义的方式”(C++ 不允许,但无论如何都很难阻止实现),并且 MS 实现似乎将 void main() 定义为一种实现定义的方式。详情请见What should main() return in C/C++
  • @Jonathan Leffler “实现定义方式”仅与函数参数的数量和类型有关。 main 的所有实现定义的声明都应具有返回类型 int。
  • 这不是标准的简单英语所说的。引用:5.1.2.2.1 程序启动 程序启动时调用的函数名为main。实现没有声明这个函数的原型。它应该用int 的返回类型定义并且没有参数:int main(void) { /* ... */ } 或有两个参数(这里称为argcargv,尽管可以使用任何名称,因为它们是本地的声明它们的函数):int main(int argc, char *argv[]) { /* ... */ } 或等效项;10)或以其他一些实现定义的方式。
  • 'or in some other implementation-defined way'前面的分号表示这种替代方式不受之前的限制。
  • C++ 标准所说的与这个仅用 C 标记的问题无关。你是对的; C++ 标准 不同并且 比C 更严格。你不能在C++ 中调用main;你可以在 C 等中。我已经交叉引用了答案(尤其是 mine)详细说明的问题,包括 C 和 C++ 之间的对比。
【解决方案4】:

根据 ANSI C,每个函数都有一个默认返回类型为整数。这就是为什么 this 不会给出错误(未指定返回)的原因。

int f() {
        printf("hmm\n"); 
}



f() {
    return 10.1; 
}

输出将是 10 或者它会给出错误取决于......

【讨论】:

    猜你喜欢
    • 2012-12-04
    • 2021-12-15
    • 2012-08-03
    • 2020-05-26
    • 1970-01-01
    • 2019-01-20
    • 2017-06-20
    • 2012-04-19
    • 2011-05-07
    相关资源
    最近更新 更多