为什么这段代码仍然有效?

use*_*747 29 c undefined-behavior

我刚遇到的一些旧代码:

MLIST * new_mlist_link()
{
    MLIST *new_link = (MLIST * ) malloc(sizeof(MLIST));
    new_link->next  = NULL;
    new_link->mapi  = NULL;
    new_link->result = 0;
}
Run Code Online (Sandbox Code Playgroud)

这被称为构建一个链表,但我注意到没有声明:

return new_link;
Run Code Online (Sandbox Code Playgroud)

即使没有返回语句,列表仍然可以正确构建.为什么会这样?

编辑:平台:Mandriva 2009 64位Linux 2.6.24.7-服务器GCC 4.2.3-6mnb1

编辑:有趣......这段代码也成功运行了大约5种不同的Linux安装,所有不同的版本/风格,以及Mac.

Ari*_*yck 35

在32位Windows上,大多数情况下,函数的返回值保留在EAX寄存器中.类似的设置在其他操作系统中使用,当然它是特定于编译器的.这个特定的函数可能会将new_link变量存储在同一个位置,因此当您返回时没有返回时,该位置的变量被调用者视为返回值.

这是不可移植的,实际上非常危险,但也是使C编程非常有趣的小事之一.

  • +1,另外它是ABI,而不是定义调用约定的操作系统. (4认同)
  • @peachykeen gcc会用`-Wall'来警告这个问题,但让我感到困惑的是为什么语言规范不会使这成为一个强制性的编译器错误.我想不出有什么理由允许这样做是个好主意. (4认同)
  • @Bryan:是的,[`-Wall`](http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html)打开`-Wreturn-type`. (2认同)
  • 为"让C编程变得如此有趣"的小东西+1 (2认同)
  • @Tyler:允许编译器(非致命地)诊断它,因为它总是适用于任何事情.但是,在标准C的一般情况下,要求缺少return语句是错误的,因为你不能指示永远不会返回的函数(例如调用abort或longjmp的函数):`int f(){int n = might_abort(); if(n)返回n; do_longjmp(); }` (2认同)

in7*_*70x 7

可能它只是使用EAX寄存器,它通常存储被调用的最后一个函数的返回值.这根本不是好习惯!这种事情的行为是不明确的..但看到工作很酷;-)


Whi*_*ind 5

这基本上是运气; 显然,编译器恰好将new_link粘贴到它会粘贴返回值的相同位置.


Geo*_*che 5

要避免此问题,请使用:

-Wreturn-type:

每当使用默认为int的返回类型定义函数时发出警告.还要警告任何return语句没有返回值,返回类型不是void的函数(从函数体的末尾掉下来被认为是没有值返回),以及一个函数中带有表达式的return语句return-type无效.

-Werror=return-type 把上面变成一个错误:

将指定的警告变为错误.附加警告的说明符,例如-Werror = switch将-Wswitch控制的警告转换为错误.此开关采用否定形式,用于否定特定警告的错误,例如-Wno-error = switch使-Wswitch警告不是错误,即使-Werror生效也是如此.您可以使用-fdiagnostics-show-option选项通过控制它的选项修改每个可控警告,以确定使用此选项的内容.

(来自海湾合作委员会的警告选项)