我刚遇到的一些旧代码:
MLIST * new_mlist_link()
{
MLIST *new_link = (MLIST * ) malloc(sizeof(MLIST));
new_link->next = NULL;
new_link->mapi = NULL;
new_link->result = 0;
}
这被称为构建一个链表,但是我注意到没有声明:
return new_link;
即使没有返回语句,列表仍然可以正确构建。为什么会这样?
编辑:平台:Mandriva 2009 64位Linux 2.6.24.7-服务器GCC 4.2.3-6mnb1
编辑:有趣......这段代码也在大约5种不同的Linux安装,所有不同的版本/口味以及Mac上成功运行。
答案 0 :(得分:35)
在32位Windows上,大多数情况下,函数的返回值保留在EAX寄存器中。类似的设置在其他操作系统中使用,当然它是特定于编译器的。此特定函数可能将new_link变量存储在同一位置,因此当您返回时没有返回时,该位置的变量被调用者视为返回值。
这是不可移植的,实际上非常危险,但也是使C编程非常有趣的小事之一。
答案 1 :(得分:7)
可能它只是使用EAX寄存器,它通常存储被调用的最后一个函数的返回值。这根本不是好习惯!这种事情的行为是不确定的..但看到工作很酷; - )
答案 2 :(得分:5)
这基本上是运气;显然,编译器碰巧将new_link粘贴到它会粘贴返回值的相同位置。
答案 3 :(得分:5)
要避免此问题,请使用:
-Wreturn-type
:
每当使用默认为int的返回类型定义函数时发出警告。还要警告任何return语句没有返回值,返回类型不是void的函数(从函数体的末尾掉落被认为是没有值返回),以及一个函数中带有表达式的return语句return-type无效。
-Werror=return-type
将上述内容变为错误:
将指定的警告变为错误。附加警告的说明符,例如-Werror = switch将-Wswitch控制的警告转换为错误。此开关采用否定形式,用于否定特定警告的错误,例如-Wno-error = switch使-Wswitch警告不是错误,即使-Werror生效也是如此。您可以使用-fdiagnostics-show-option选项通过控制它的选项修改每个可控警告,以确定使用此选项的内容。
答案 4 :(得分:1)
这巧合。你不应该依赖它。
答案 5 :(得分:1)
最有可能的是它会产生很难找到的bug。我不确定我在哪里阅读它,但我记得如果你忘记输入一个返回语句,大多数编译器将默认返回void。
这是一个简短的例子:
#include <iostream>
using namespace std;
int* getVal();
int main()
{
int *v = getVal();
cout << "Value is: " << *v << endl;
return 0;
}
int* getVal()
{
// return nothing here
}
对我来说,这也有效。但是,当我运行它时,我得到一个段错误。所以它确实是未定义的。仅仅因为它编译,并不意味着它会起作用。
答案 6 :(得分:0)
这很有效,因为在1940年创建C语言时,没有return
个关键字。如果您查看C43 MINSI标准的“功能”部分,可以就此主题(以及其他内容)进行说明:
16.4.3b For backwards compatibility the EAX register MUST be used to return
the address of the first chunk of memory allocated by malloc.
</humour>
答案 7 :(得分:-1)
可能是巧合:
提前分配函数返回值的空间。由于该值未初始化,因此可能指向堆上的相同空间作为为结构分配的内存。