C++ 当一个函数带有“警告”时(实际上)会发生什么;控制达到非无效函数的末尾“;叫什么名字?

C++ 当一个函数带有“警告”时(实际上)会发生什么;控制达到非无效函数的末尾“;叫什么名字?,c++,c,C++,C,我知道这条消息的意思,我只是想知道为什么它不是一条错误消息,而只是一条警告 在这种情况下会发生什么?例如,假设我有一个函数 int f() { } 当我叫它时会发生什么? 在这种情况下,编译器是否会添加返回“未初始化”int 或者丢失的返回可能导致堆栈损坏? 还是(绝对)未定义的行为 按照gcc 4.1.2和4.4.3进行测试 编辑:阅读答案我理解一件事,阅读评论-另一件 好的,让我们总结一下:这是未定义的行为。那么,这意味着,有可能导致堆栈损坏,对吗?(这甚至意味着,我的电脑可能开始通过麦

我知道这条消息的意思,我只是想知道为什么它不是一条错误消息,而只是一条警告

在这种情况下会发生什么?例如,假设我有一个函数

int f()
{
}
当我叫它时会发生什么?
在这种情况下,编译器是否会添加返回“未初始化”
int
或者丢失的返回可能导致堆栈损坏?
还是(绝对)未定义的行为

按照gcc 4.1.2和4.4.3进行测试


编辑:阅读答案我理解一件事,阅读评论-另一件

好的,让我们总结一下:这是未定义的行为。那么,这意味着,有可能导致堆栈损坏,对吗?(这甚至意味着,我的电脑可能开始通过麦克风插孔向我扔腐烂的西红柿,尖叫着“你做了什么?”)

但如果是这样的话,那么为什么这里的首要答案是,堆栈损坏不会发生,同时,行为是未定义的

并且未定义关于?试图使用“not returned value”的调用方,或者如果必须返回值,则函数的结尾未定义,但它没有返回值


或者,这不是未定义的行为,只有尝试使用该值(没有返回,哦!)的用户才会“接收”未定义的值?换句话说-只有一些垃圾值,不会再发生任何事情了?

A:不,丢失的返回不会导致堆栈损坏

答:是的,如果调用方试图读取和/或使用(未定义!)返回值,则行为将为“未定义”

附言:

下面是对C++的引用:

C++03§6.6.3/2:

从函数末尾流出相当于返回,而不返回 价值这将导致返回值时出现未定义的行为 功能


编译器不需要对此进行诊断,因为在某些情况下,它很难诊断。因此规则是行为未定义。

标准认为它未定义

实际上,将读取为返回值保留的内存或寄存器。有什么就有什么。

6.9.1功能定义 …
12如果达到终止函数的
}
,并且函数调用的值由 来电者的行为尚未确定。 “未定义”只是指语言标准不要求编译器以任何特定方式处理这种情况;任何行动都被认为是“正确的”。编译器可以自由地发出诊断并停止翻译,或者发出诊断并完成翻译(这就是您看到的),或者完全忽略问题

至于实际的运行时行为,这取决于以下情况:

  • 调用者如何使用返回值
  • 正在使用的呼叫约定是什么
  • 底层架构是如何工作的

你问C和C++两个问题。两种语言的规则不同

在C语言中,只有当调用方试图使用函数返回的值时,行为才是未定义的。如果您有:

int func(void) {
    /* no return statement */
}

...

func();
那么行为就有了明确的定义

在C++中,如果调用方试图使用结果,则行为是未定义的(如果函数被调用)。(这是出于历史原因;ANSI C之前没有
void
关键字,不打算返回值的函数通常(隐式)定义为返回
int

John Bode的回答已经引用了2011年ISO C标准第6.9.1p12节:

如果达到终止函数的},则 调用方使用函数调用,行为未定义

和PaulSM4引用C++标准;引用2011年最新版本6.6.3p2:

从函数末尾流出相当于返回一个没有 价值这将导致返回值时出现未定义的行为 功能

导致C返回值返回函数失败的历史原因,只要调用方不使用该值,就不适用于C++,其设计不受需要避免破坏旧(ANSI前C)代码的强烈影响。

在C(C99)和C++中,<>代码> < < /代码>函数是一个特例;在不执行返回的情况下到达

main
的关闭
}
,相当于
返回0。(C允许
main
返回除
int
以外的实现定义的类型;在这种(罕见)情况下,从末端脱落会向主机环境返回未指定的终止状态。)


当然,从值返回函数中省略
return
语句,或者可能的执行路径没有到达
return
语句,这是一个坏主意。只有在使用
int
作为
void
替代的古代遗留C代码中,以及在
main
中,它才有意义(尽管即使对于
main
,我个人也希望显式
返回0;
)。

我在64位Linux GCC 4.63上进行了一个简单的测试 让我们看看GCC如何在实践中组装这样的东西

我创建了一个简单的示例

这是具有正常返回值的test.c

int main()
{
    return 0;
}
int main()
{
}
这是测试的GCC汇编程序输出。c:

main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
这是test2.c,没有返回值

int main()
{
    return 0;
}
int main()
{
}
这是test2.c的GCC汇编程序输出:

main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
基本上,我们可以看到下面这一行缺失了

    movl    $0, %eax
此行将一个值移动到
eax
寄存器,该寄存器是函数的返回值。如果函数用于实际情况,则可能包含垃圾值的
eax
寄存器将表示返回值