为什么这段代码仍然有效?
我刚刚遇到的一些旧代码:
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;
即使那里没有 return 语句,列表仍然可以正确构建。为什么会发生这种情况?
编辑: 平台:Mandriva 2009 64位 Linux 2.6.24.7-server GCC 4.2.3-6mnb1
编辑: 有趣...此代码也在大约 5 个不同的 Linux 安装上成功运行,所有不同版本/风格,以及 Mac。
Some old code that I just came across:
MLIST * new_mlist_link()
{
MLIST *new_link = (MLIST * ) malloc(sizeof(MLIST));
new_link->next = NULL;
new_link->mapi = NULL;
new_link->result = 0;
}
This was being called to build a linked list, however I noticed there is no statement:
return new_link;
Even without the return statement there, the list still got built properly. Why did this happen?
Edit: Platform: Mandriva 2009 64bit Linux 2.6.24.7-server GCC 4.2.3-6mnb1
Edit: Funny... this code also ran successfuly on about 5 different Linux installations, all different versions/flavors, as well as a Mac.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
在 32 位 Windows 上,大多数时候,函数的返回值保留在 EAX 寄存器中。其他操作系统中也使用类似的设置,当然它是特定于编译器的。这个特定的函数可能将 new_link 变量存储在同一位置,因此当您返回而不返回时,该位置中的变量将被调用者视为返回值。
这是不可移植的,而且实际执行起来非常危险,但也是让 C 编程变得如此有趣的小事情之一。
On 32-bit Windows, most of the time, the return value from a function is left in the EAX register. Similar setups are used in other OSes, though of course it's compiler-specific. This particular function presumably stored the new_link variable in that same location, so when you returned without a return, the variable in that location was treated as the return value by the caller.
This is non-portable and very dangerous to actually do, but is also one of the little things that makes programming in C so much fun.
可能它只是使用了 EAX 寄存器,该寄存器通常存储最后一个被调用函数的返回值。这根本不是一个好的做法!这类事情的行为是未定义的..但是看到工作很酷;-)
Possible it just used the EAX register which normally stores the return value of the last function that was called. This is not good practice at all! The behavior for this sort of things is undefined.. But it is cool to see work ;-)
这基本上是运气;显然,编译器碰巧将 new_link 粘贴到粘贴返回值的同一位置。
It's basically luck; apparently, the compiler happens to stick new_link into the same place it would stick a returned value.
要避免此问题,请使用:
-Wreturn-type
:-Werror=return-type
将上面的内容变成错误:(来自 GCC 警告选项)
To avoid this problem, use:
-Wreturn-type
:-Werror=return-type
to turn the above into an error:(from GCCs warning options)
这是巧合。你不应该依赖它。
This works by coincidence. You shouldn't rely on that.
最有可能的是,它会产生一个很难发现的错误。我不确定我在哪里读到它,但我记得如果你忘记放入 return 语句,大多数编译器将默认返回 void。
这是一个简短的例子:
对我来说,这也有效。但是,当我运行它时,我遇到了段错误。所以它确实是未定义的。仅仅因为它可以编译,并不意味着它会起作用。
Most likely is that it'll produce a very hard to find bug. I'm unsure where I read it, but I recall that if you forget to put in a return statement, most compilers will default to return void.
Here's a short example:
For me, this works as well. However, when I run it, I get a segment fault. So it's really undefined. Just because it compiles, doesn't mean it'll work.
它之所以有效,是因为在 20 世纪 40 年代 C 语言创建时,还没有
return
关键字。如果您查看 C43 MINSI 标准的“函数”部分,它对这个主题有这样的说法(除其他外):It works because in the 1940's when the C language was created, there was no
return
keyword. If you look in the "functions" section of the C43 MINSI standard, it has this to say on the subject (amongst other things):</humour>
可能是巧合:
函数返回值的空间是提前分配的。由于该值未初始化,因此它可能指向堆上与为结构分配的内存相同的空间。
Probably a coincidence:
The space for the return value of the function is allocated ahead of time. Since that value is uninitialized, it could have pointed to the same space on the heap as the memory allocated for the struct.