gpt4 book ai didi

c - 该标准是否对没有返回类型的函数有任何规范性措辞?

转载 作者:行者123 更新时间:2023-12-01 08:25:46 25 4
gpt4 key购买 nike

尽管许多编译器都可以容忍没有返回类型的函数,但 N1570 的标准似乎没有规范性的措辞。为什么会这样?

最佳答案

在最初的 C 标准(C89、C90)中,第 6.7.1 节涵盖了函数定义。在 C99 和 C11 标准中,第 6.9.1 节涵盖了函数定义。两者之间有一个很小但至关重要的区别。

ISO/IEC 9899:1990

§6.7.1 Function definitions

Syntax

  function definition:
          declaration-specifiersopt   declarator   declaration-listopt   compound-statement



ISO/IEC 9899:1999 和 ISO/IEC 9899:2011

§6.9.1 Function definitions

Syntax

¶1  function definition:
          declaration-specifiers   declarator   declaration-listopt   compound-statement



在标准的更高版本中,声明说明符中缺少下标 opt。

这就是控制返回类型的任何标准的“函数定义”部分中的全部内容。

接下来的两段在标准的所有三个版本之间都是通用的(尽管我省略了一个带有不同数字的脚注)。

¶2 The identifier declared in a function definition (which is the name of the function) shall have a function type, as specified in the declarator portion of the function definition.

¶3 The return type of a function shall be void or a complete object type other than array type.



声明说明符可以省略类型(因此它可以声明 staticextern 而没有类型)。在 C90 中,这是合法的;在 C99 和 C11 中,这是不允许的。与此相关的部分是 C90 中的 §6.5.2 和 C99 和 C11 中的 §6.7.2,用于类型说明符。

ISO/IEC 9899:1990

Type specifiers

Constraints
Each list of type specifiers shall be one of the following sets (delimited by commas, when there is more than one set on a line); the type specifiers may occur in any order, possibly intermixed with the other declaration specifiers.



ISO/IEC 9899:1999 和 ISO/IEC 9899:2011

6.7.2 Type specifiers

Constraints
At least one type specifier shall be given in the declaration specifiers in each declaration, and in the specifier-qualifier list in each struct declaration and type name. Each list of type specifiers shall be one of the following sets (delimited by commas, when there is more than one set on a line); the type specifiers may occur in any order, possibly intermixed with the other declaration specifiers.



C99/C11 文本中的第一句排除了不包含类型的声明说明符的可能性,而 C90 没有提及这一点,因此声明说明符可以省略类型。

执法

直到最近(GCC 5),GNU C 编译器使用 C90 标准作为其默认操作模式,因此在允许没有显式返回类型的函数定义方面很松懈,因为 C90 标准对此很松懈。鉴于 C 代码在 1989 年或 1990 年的状态,这种松懈是必要的,因为当时许多现有代码不包含返回类型。如果 C90 标准对此非常严格,它就会失败。事实上,它非常成功。

从 GCC 5.1 开始,GNU C 编译器默认将 C11 标准作为其默认操作模式,因此它会生成有关未定义返回类型的函数的警告。如果您愿意,可以将这些警告转换为错误。让我们重申一下:你 应该 将这些警告转换为错误,然后修复代码以便不再生成警告。

考虑存储在文件 old-style.c 中的草率(按照现代标准)代码:
function(int x)
{
return 2 * x * x + 3 * x - 7;
}

在使用 GCC 6.3.0 在运行 macOS Sierra 10.12.4 的 Mac 上编译,我得到:
$ gcc -c old-style.c
old-style.c:1:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
function(int x)
^~~~~~~~
$ gcc -std=c11 -c old-style.c
old-style.c:1:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
function(int x)
^~~~~~~~
$ gcc -std=c99 -c old-style.c
old-style.c:1:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
function(int x)
^~~~~~~~
$ gcc -std=c90 -c old-style.c
$

因此,只有指定了 C90 标准,我才能在默认选项下获得“干净”(无警告)编译。

添加 -Werror-Werror=implict-int将这些警告转换为错误:
$ gcc -Werror -std=c11 -c old-style.c
old-style.c:1:1: error: return type defaults to ‘int’ [-Werror=implicit-int]
function(int x)
^~~~~~~~
cc1: all warnings being treated as errors
$ gcc -Werror=implicit-int -std=c11 -c old-style.c
old-style.c:1:1: error: return type defaults to ‘int’ [-Werror=implicit-int]
function(int x)
^~~~~~~~
cc1: some warnings being treated as errors
$

不同的是,普通的 -Werror将所有警告变为错误,但 -Werror=implicit-int将该警告变为错误(其他警告仍为警告)。

我自己的编码标准要求在定义或使用非静态函数之前使用完整的原型(prototype)声明它。在使用静态函数之前,可以在没有事先原型(prototype)的情况下定义它们。此外,任何非静态函数声明都应该在标题中;函数不是静态的唯一原因是因为它将被另一个源文件使用,并且头文件对于允许编译器检查定义函数的位置和使用它的位置之间的一致性是必要的。
因此,我的默认编译选项是:
$ gcc -Wall -Wextra -Werror -Wstrict-prototypes -Wmissing-prototypes \
> -Wold-style-declaration -Wold-style-definition -std=c11 -c old-style.c
old-style.c:1:1: error: return type defaults to ‘int’ [-Werror=implicit-int]
function(int x)
^~~~~~~~
old-style.c:1:1: error: no previous prototype for ‘function’ [-Werror=missing-prototypes]
cc1: all warnings being treated as errors
$

某些版本的 GCC 不支持 -Wold-style-xxx选项,而 Clang 不喜欢 -Wold-style-declaration选项,所以我经常省略。

修复 new-style.c相当容易:
extern int function(int x);     /* Should be in a header */

int function(int x)
{
return 2 * x * x + 3 * x - 7;
}

并且在严格的编译选项下编译,几乎没有吱吱声:
$ gcc -Wall -Wextra -Werror -Wstrict-prototypes -Wmissing-prototypes \
> -Wold-style-declaration -Wold-style-definition -std=c11 -c new-style.c
$

其他编译器的规则与 GCC 类似——不同的版本可能会做不同的事情,默认情况下会提示不同的问题,并且需要不同的选项来使它们产生您需要的诊断。使用多个编译器(最好是在多个平台上)来检查代码的运行情况总是有帮助的。

关于c - 该标准是否对没有返回类型的函数有任何规范性措辞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34515884/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com