为什么C标准不允许从函数返回值?
我已在gcc中成功编译并执行了以下代码:为什么C标准不允许从函数返回值?,c,gcc,C,Gcc,我已在gcc中成功编译并执行了以下代码: #include <stdio.h> int foo() { } int main() { int i = 12345; i = foo(); printf("i is: %d", i); } 因此gcc允许我不从函数foo()返回,并使foo()返回0 这种行为只适用于gcc还是其他C标准也有这种行为(根据我的理解,gcc不符合任何C标准)?好吧,标准中没有任何东西可以阻止您编写非法代码,但是,它确实提到这是
#include <stdio.h>
int foo()
{
}
int main()
{
int i = 12345;
i = foo();
printf("i is: %d", i);
}
因此gcc允许我不从函数foo()
返回,并使foo()
返回0
这种行为只适用于gcc还是其他C标准也有这种行为(根据我的理解,gcc不符合任何C标准)?好吧,标准中没有任何东西可以阻止您编写非法代码,但是,它确实提到这是未定义的行为 引用第§6.9.1章中的
C11
如果到达终止函数的}
,并且函数调用的值由
调用方的行为未定义
嗯,标准中没有任何东西可以阻止您编写非法代码,但是,它确实提到这是未定义的行为 引用第§6.9.1章中的
C11
如果到达终止函数的}
,并且函数调用的值由
调用方的行为未定义
如果函数缺少返回语句,则没有任何C标准要求编译器生成错误或警告 在所有的C标准中,如果控制流到达非无效函数的末尾而没有返回值,则行为是未定义的,然后使用函数的返回值(如代码中所示) 因此,如果“允许”的意思是“将其指定为合法的、定义良好的行为”,那么没有一个C标准允许您的代码。如果您的意思是“不需要实现来产生错误”,那么它们都会产生错误 请注意,如果更改
foo
的定义(无需添加返回值),示例程序中i
的值很容易更改。你不能指望它是0。无论是在标准中还是在GCC的实现中,都没有规定“如果没有返回,则返回0”。根据标准,它是未定义的,在GCC中,它只是返回寄存器中当时发生的任何事情
在一般情况下,这是不可判定的。人们可以像Java这样做,并定义规则,从而拒绝一些本来有效的函数定义,但没有一个C标准这样做。如果函数缺少返回语句,没有一个C标准要求编译器生成错误或警告
在所有的C标准中,如果控制流到达非无效函数的末尾而没有返回值,则行为是未定义的,然后使用函数的返回值(如代码中所示)
因此,如果“允许”的意思是“将其指定为合法的、定义良好的行为”,那么没有一个C标准允许您的代码。如果您的意思是“不需要实现来产生错误”,那么它们都会产生错误
请注意,如果更改foo
的定义(无需添加返回值),示例程序中i
的值很容易更改。你不能指望它是0。无论是在标准中还是在GCC的实现中,都没有规定“如果没有返回,则返回0”。根据标准,它是未定义的,在GCC中,它只是返回寄存器中当时发生的任何事情
在一般情况下,这是不可判定的。人们可以像Java那样做,定义规则,从而拒绝一些本来有效的函数定义,但没有一个C标准会这样做。gcc确实给出了警告:
警告:控件到达非无效函数的末尾[-Wreturn类型]|
(免责声明:我从不同版本的gcc中得到不同的结果。可以肯定的是,使用-Wall-Wextra-pedantic errors
编译)
在这种情况下发生的情况不在C标准的范围内。本标准仅说明(C116.9.1/12):
如果到达终止函数的},并且调用方使用了函数调用的值,则行为未定义
在您的情况下,调用方通过将返回值存储在i
中来使用返回值。因此,这是未定义的行为-该行为不在C标准中,编译器没有义务通知您。任何事情都有可能发生。因此,在大多数情况下,这应该被视为一个bug。gcc确实给出了警告:
警告:控件到达非无效函数的末尾[-Wreturn类型]|
(免责声明:我从不同版本的gcc中得到不同的结果。可以肯定的是,使用-Wall-Wextra-pedantic errors
编译)
在这种情况下发生的情况不在C标准的范围内。本标准仅说明(C116.9.1/12):
如果到达终止函数的},并且调用方使用了函数调用的值,则行为未定义
在您的情况下,调用方通过将返回值存储在i
中来使用返回值。因此,这是未定义的行为-该行为不在C标准中,编译器没有义务通知您。任何事情都有可能发生。因此,在大多数情况下,这应该被视为一个bug。我认为在这种情况下,未定义的行为在最流行的编译器之间非常常见。如果您反汇编foo
函数,您将在几乎所有版本的gcc中找到以下说明:
push rbp
mov rbp, rsp
nop
pop rbp
ret
这段代码什么也没做,正是你想要的。但是,它甚至不遵循调用约定规则,无论何时预期函数的结果。结果应该通过eax/rax
寄存器传递给调用者。在foo
中,这个寄存器甚至没有被修改,这就是为什么会出现未定义的行为
省略报税表就像说:“我不想遵守你给我的规则”clang
生成类似的代码,我想其他编译器(除非应用了进一步的选项或优化)的原因是
push rbp
mov rbp, rsp
nop
pop rbp
ret
int i = 12345;
int m = 12345;
m *= 3;
i = foo();
printf("i is: %d", i);
If a return statement without an expression is
executed, and the value of the function call
is used by the caller, the behavior is undefined.