Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么C标准不允许从函数返回值?_C_Gcc - Fatal编程技术网

为什么C标准不允许从函数返回值?

为什么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标准)?好吧,标准中没有任何东西可以阻止您编写非法代码,但是,它确实提到这是

我已在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标准)?

好吧,标准中没有任何东西可以阻止您编写非法代码,但是,它确实提到这是未定义的行为

引用第§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.