c++ - 为什么为不返回任何内容的函数声明返回值只会导致 gcc8 中的运行时崩溃
问题描述
在以下代码中,函数被声明/定义为int setYear(int year_h){year = year_h;}
(而不是void setYear(...)
,导致 gcc 8 中的运行时崩溃并且-O[X]
仅带有标志。
具体问题:
- gcc 8 中发生了什么变化,因为它在 gcc 7 中工作?
- 我可以使用哪些标志(如果有)在 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 之间的区别)。
解决方案
从 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
(.string
s 在另一部分中声明),再次执行它而不是返回调用点。显然,当函数中除了返回 non-之外RET
没有语句时,gcc 认为不值得添加指令。return
main
void
当然,在许多情况下,编译器在编译阶段很容易检测到问题。我建议-Werror=return-type
无条件地使用选项,这会导致错误(与-Werror
一般情况不同)。当您想要避免此选项时,这是非常罕见的,而且它非常有用。
推荐阅读
- python - 最优联盟结构
- c# - C# 中 *is* 关键字的新条件语法
- python - python - TypeError:'NoneType'对象不可调用
- node.js - 处理不同的路由 node.js
- c++ - C ++中迭代器类中的运算符重载
- sql - 如何获取小于或等于当前日期的最新“生效日期”
- html - 如何使用 div 和 label 组件制作类似字段集的组件?
- rxjs - Angular2:在调用方法之前获取服务的属性值
- docker - Docker-compose 完全忽略了我包含环境变量的文件
- java - Eclipse Maven 项目:是否可以将一个版本的 JDK 用于项目,而将另一个版本的 JDK 用于测试?