首页 > 解决方案 > 为什么为不返回任何内容的函数声明返回值只会导致 gcc8 中的运行时崩溃

问题描述

在以下代码中,函数被声明/定义为int setYear(int year_h){year = year_h;}(而不是void setYear(...),导致 gcc 8 中的运行时崩溃并且-O[X]仅带有标志。

具体问题:

  1. gcc 8 中发生了什么变化,因为它在 gcc 7 中工作?
  2. 我可以使用哪些标志(如果有)在 gcc8 中生成编译错误(而不是警告)?

主.cpp:

#include <iostream>

using namespace std;

int year = 2000;
int setYear(int year_h){year = year_h;}

int main()
{
    cout << "Hello World!" << endl;
    setYear(2019);
    cout << "Year: " << year << endl;
    return 0;
}

运行时崩溃:

g++-8 -O2  -o main main.cpp
./main
Hello World!
Hello World!
Segmentation fault (core dumped)

适用于:

g++-7 -O2  -o main main.cpp

或者

g++-8 -o main main.cpp

编辑:在 C++ 中省略返回语句的问题回答了我的第二个问题,但不是第一个问题(关于 gcc 7 和 gcc 8 之间的区别)。

标签: c++pointersgccgcc8

解决方案


从 GCC 8 开始,您的setYear函数在编译源代码时根本没有RET指令-Og(在更高级别,函数是内联的,这使得理解正在发生的事情变得更加困难),并且main调用函数的位置也缺乏任何延续。

请参阅Compiler Explorer 中的原始代码进行比较:

<...>
setYear(int):
        mov     DWORD PTR year[rip], edi
.LC0:
        .string "Hello World!"
main:
<...>

并且返回类型int已更改为void链接)的代码:

<...>
setYear(int):
        mov     DWORD PTR year[rip], edi
        ret
.LC0:
        .string "Hello World!"
.LC1:
        .string "Year: "
main:
<...>

仅此省略就足以使执行流程遇到main.strings 在另一部分中声明),再次执行它而不是返回调用点。显然,当函数中除了返回 non-之外RET没有语句时,gcc 认为不值得添加指令。returnmainvoid

当然,在许多情况下,编译器在编译阶段很容易检测到问题。我建议-Werror=return-type无条件地使用选项,这会导致错误(与-Werror一般情况不同)。当您想要避免此选项时,这是非常罕见的,而且它非常有用。


推荐阅读