【C/C++ 关键字 函数说明符 】C/C++ _Noreturn关键字(表明调用完成后函数不返回主调函数)

简介: 【C/C++ 关键字 函数说明符 】C/C++ _Noreturn关键字(表明调用完成后函数不返回主调函数)

1. 引言:_Noreturn关键字的简介

1.1 _Noreturn关键字的定义

在C++中,_Noreturn(在C++中通常写作[[noreturn]])是一个函数属性,它表明函数在执行完毕后不会返回到调用者。这个关键字在C11和C++11中引入,用于标记那些不会返回的函数。

例如,我们可以这样定义一个_Noreturn函数:

[[noreturn]] void suicide() {
    abort(); // Actually, abort is _Noreturn as well
}

在这个例子中,suicide函数被标记为[[noreturn]],这意味着一旦调用这个函数,它就不会返回到调用者。这是因为abort函数(它也是一个[[noreturn]]函数)会终止程序的执行。

在英语口语中,我们通常会说 “The function suicide is marked as [[noreturn]], which means it won’t return to its caller once it’s invoked.”(函数suicide被标记为[[noreturn]],这意味着一旦调用它,它就不会返回到调用者。)

1.2 _Noreturn与void的区别

_Noreturnvoid都是函数的返回类型,但它们的含义是不同的。void表示函数没有返回值,但是函数执行完毕后会返回到调用者。而_Noreturn则表示函数执行完毕后不会返回到调用者。

例如,我们可以定义一个void函数如下:

void doNothing() {
    // do nothing
}

在这个例子中,doNothing函数的返回类型是void,这意味着它没有返回值。但是,一旦调用这个函数,它会执行完毕后返回到调用者。

在英语口语中,我们通常会说 “The function doNothing is a void function, which means it doesn’t return a value but it will return to its caller after it finishes execution.”(函数doNothing是一个void函数,这意味着它没有返回值,但是它会在执行完毕后返回到调用者。)

下表总结了_Noreturnvoid的主要区别:

返回类型 是否有返回值 是否返回到调用者
_Noreturn
void

在接下来的章节中,我们将深入探讨_Noreturn关键字的设计意图、使用场景、底层原理和实际应用案例。

2. _Noreturn关键字的设计意图

2.1 为什么需要_Noreturn关键字

在C++中,_Noreturn(不返回)关键字的设计初衷是为了处理那些不会返回到调用者的函数。这种函数在执行完毕后,不会返回到调用它的代码位置。这与void类型的函数有所不同,void类型的函数在执行完毕后会返回到调用它的代码位置,只是它不提供返回值。

在实际编程中,我们可能会遇到一些特殊的函数,这些函数在被调用后,可能会导致程序终止,或者进入一个无限循环,或者抛出一个异常,这些情况下,函数都不会返回到调用它的地方。为了处理这种情况,C++引入了_Noreturn关键字。

例如,exit()函数就是一个典型的_Noreturn函数。一旦调用exit()函数,程序就会立即终止,不会返回到调用exit()的地方。这就是_Noreturn关键字的一个典型应用。

2.2 _Noreturn关键字的优化作用

_Noreturn关键字不仅可以帮助我们处理那些不会返回的函数,还可以帮助编译器进行一些优化。

当编译器看到一个函数被声明为_Noreturn时,它就知道这个函数不会返回到调用它的地方。这样,编译器就可以在生成代码时,省略掉一些不必要的操作,比如保存和恢复寄存器的值,或者设置返回地址等。这样可以使生成的代码更加高效。

此外,_Noreturn关键字还可以帮助编译器进行一些代码检查。例如,如果一个函数被声明为_Noreturn,但是在实际的代码中,这个函数有可能返回到调用它的地方,那么编译器就会发出警告。

下面是一个_Noreturn关键字的使用示例:

_Noreturn void suicide() {
    abort(); // 实际上,abort也是_Noreturn的
}

在这个例子中,suicide()函数被声明为_Noreturn,这意味着这个函数在被调用后不会返回。在函数体中,我们调用了abort()函数,abort()函数会导致程序立即终止,所以suicide()函数确实不会返回。

3. _Noreturn关键字的使用场景

3.1 在哪些情况下使用_Noreturn关键字

_Noreturn关键字在C++中的使用场景相对有限,但在某些特定的情况下,它的作用却是不可或缺的。通常,我们在设计那些不会返回到调用者的函数时使用_Noreturn关键字,例如,终止程序的函数,或者抛出异常的函数。

在C++中,我们通常会在以下几种情况下使用_Noreturn关键字:

  • 终止程序:例如,exit()函数和abort()函数。这些函数一旦被调用,程序就会立即终止,不会返回到调用者。
  • 抛出异常:例如,throw语句。如果一个函数只包含throw语句,那么它就不会返回到调用者。
  • 无限循环:例如,while(true) {}。如果一个函数包含无限循环,那么它也不会返回到调用者。

在口语交流中,我们通常会这样描述_Noreturn关键字的使用场景:“The _Noreturn keyword is used in functions that do not return to the caller, such as functions that terminate the program, throw exceptions, or contain infinite loops." (我们在那些不会返回到调用者的函数中使用_Noreturn关键字,例如,终止程序的函数,抛出异常的函数,或者包含无限循环的函数。)

3.2 _Noreturn关键字的使用限制

尽管_Noreturn关键字在某些情况下非常有用,但我们在使用它时也需要注意一些限制:

  • _Noreturn关键字只能用于函数声明,不能用于函数定义。
  • _Noreturn关键字必须出现在函数声明的最开始部分,不能出现在其他地方。
  • 如果一个函数被声明为_Noreturn,那么它必须确保不会返回到调用者。如果它返回到了调用者,那么结果是未定义的。

在口语交流中,我们通常会这样描述_Noreturn关键字的使用限制:“The _Noreturn keyword can only be used in function declarations, not in function definitions. It must appear at the beginning of the function declaration, and cannot appear elsewhere. If a function is declared as _Noreturn, it must ensure that it does not return to the caller. If it does, the result is undefined." (我们只能在函数声明中使用_Noreturn关键字,不能在函数定义中使用。它必须出现在函数声明的最开始部分,不能出现在其他地方。如果一个函数被声明为_Noreturn,那么它必须确保不会返回到调用者。如果它返回到

了调用者,那么结果是未定义的。)

接下来,让我们通过一个综合的代码示例来看一下_Noreturn关键字的使用。

#include <stdlib.h>
_Noreturn void exit_program() {
    printf("Exiting the program...\n");
    exit(0); // exit() is a _Noreturn function
}
int main() {
    printf("Calling exit_program()...\n");
    exit_program();
    printf("This line will never be printed.\n");
    return 0;
}

在这个示例中,我们定义了一个名为exit_program()的_Noreturn函数。这个函数打印一条消息,然后调用exit(0)来终止程序。在main()函数中,我们调用了exit_program(),然后尝试打印一条消息。但是,这条消息永远不会被打印,因为exit_program()不会返回到调用者。

这个示例清楚地展示了_Noreturn关键字的作用:它告诉编译器和读者,exit_program()函数不会返回到调用者。这对于理解和优化代码非常有帮助。

在接下来的章节中,我们将深入探讨_Noreturn关键字的底层原理,以及它在高级编程中的应用。

4. _Noreturn关键字的底层原理

4.1 编译器如何处理_Noreturn关键字

在C++中,_Noreturn(中文:不返回)是一个函数说明符,它告诉编译器函数不会返回到调用者。这是通过改变编译器的行为来实现的。当编译器看到一个函数被声明为_Noreturn时,它会假设这个函数不会返回。这意味着编译器可以在生成代码时进行一些优化,例如,它可以省略保存和恢复调用者的某些状态的代码,因为它知道这些状态在函数返回时不会被需要。

在英语中,我们可以这样描述这个过程:“The compiler optimizes the code by assuming that the function declared as _Noreturn will not return to its caller.”(编译器通过假设声明为_Noreturn的函数不会返回到其调用者来优化代码。)

4.2 _Noreturn关键字对程序执行流程的影响

_Noreturn关键字对程序的执行流程有重要影响。当一个函数被声明为_Noreturn时,调用这个函数的代码必须假设函数不会返回。这意味着在调用_Noreturn函数后的代码可能永远不会被执行。这对于理解程序的控制流程非常重要。

在英语中,我们可以这样描述这个过程:“The code after the call to a _Noreturn function may never be executed, which is crucial for understanding the control flow of the program.”(调用_Noreturn函数后的代码可能永远不会被执行,这对于理解程序的控制流程至关重要。)

以下是一个带注释的代码示例,说明了_Noreturn关键字的影响:

#include <stdlib.h>
_Noreturn void exit_now() {
    exit(0); // This function will not return
}
int main() {
    exit_now(); // After this call, the following code will not be executed
    printf("This line will never be printed.\n");
    return 0;
}

在这个例子中,exit_now函数被声明为_Noreturn,所以调用exit_now后的代码(即printf语句)永远不会被执行。

下图进一步解释了_Noreturn关键字对程序执行流程的影响:

在这个图中,你可以看到,当一个函数被调用时,它会执行其代码,如果这个函数是_Noreturn,那么它不会返回到调用者。如果这个函数不是_Noreturn,那么它会在执行完毕后返回到调用者。

以下是一个更具体的例子,说明了_Noreturn函数在程序执行流程中的位置:

在这个图中,你可以看到,main函数调用了exit_now函数,exit_now函数执行了它的代码,但是它没有返回到main函数。因此,调用exit_now后的代码(即printf语句)没有被执行。

这就是_Noreturn关键字的底层原理。它通过改变编译器的行为和程序的执行流程,使得函数不会返回到调用者。这个特性可以用于一些特殊的情况,例如错误处理和程序退出,它可以使代码更简洁,更易于理解,同时还可以帮助编译器进行优化。

5. _Noreturn关键字的实际应用案例

在本章节中,我们将通过实际的代码示例来探讨_Noreturn关键字的应用。我们将首先介绍一个基本的使用_Noreturn关键字的函数示例,然后我们将深入到Qt6和qt quick中的应用,最后我们将探讨_Noreturn关键字在音视频处理中的应用。

5.1 使用_Noreturn关键字的函数示例

让我们从一个简单的例子开始,这个例子中的函数使用了_Noreturn关键字。这个函数被命名为terminate_program,它的作用是终止程序的运行。

#include <stdlib.h>
_Noreturn void terminate_program() {
    printf("Terminating the program...\n");
    exit(0);
}

在这个例子中,terminate_program函数使用了_Noreturn关键字,这意味着一旦这个函数被调用,它就不会返回到主调函数。exit(0)是一个标准库函数,它会终止程序的运行。因此,terminate_program函数的执行会导致程序的终止。

5.2 _Noreturn关键字在Qt6和qt quick中的应用

在Qt6和qt quick中,_Noreturn关键字也有一些特定的应用。例如,我们可以在一个Qt应用程序中使用_Noreturn关键字来处理致命错误。

#include <QCoreApplication>
#include <QMessageBox>
_Noreturn void handle_fatal_error(const QString &message) {
    QMessageBox::critical(nullptr, "Fatal Error", message);
    QCoreApplication::exit(1);
}

在这个例子中,handle_fatal_error函数使用了_Noreturn关键字。这个函数接收一个字符串参数message,然后显示一个包含这个消息的致命错误对话框,最后通过调用QCoreApplication::exit(1)来终止程序的运行。

5.3 _Noreturn关键字在音视频处理中的应用

在音视频处理中,我们也可以使用_Noreturn关键字来处理无法恢复的错误。例如,我们可以在使用ffmpeg库进行音视频处理时,使用_Noreturn关键字来处理无法打开输入文件的错误。

#include <libavformat/avformat.h>
_Noreturn void handle_open_input_error(int errnum) {
    char errbuf[AV_ERROR_MAX_STRING_SIZE];
    av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
    fprintf(stderr, "Could not open input file: %s\n", errbuf);
    exit(1);
}

在这个例子中,handle_open_input_error函数使用了_Noreturn关键字。这个函数接收一个错误号errnum,然后使用ffmpeg库的av_strerror函数将这个错误号转换为一个错误消息,然后将这个错误消息打印到标准错误输出,最后通过调用exit(1)来终止程序的运行。

6. _Noreturn关键字的高级话题

在这一章节中,我们将深入探讨_Noreturn关键字在元模板编程中的应用,以及它在C++11, 14, 17, 20中的变化和应用。

6.1 _Noreturn关键字在元模板编程中的应用

元模板编程(Meta-template programming)是C++中的一种技术,它允许在编译时执行计算。这种技术的一个常见应用是生成和操作类型和函数。

在元模板编程中,我们可以使用_Noreturn关键字来定义那些在编译时就能确定不会返回的函数。例如,我们可以定义一个函数,该函数在某些条件下会导致编译错误。这个函数可以被标记为_Noreturn,因为我们知道它永远不会在运行时返回。

template <typename T>
_Noreturn void fail_with_compile_error() {
    static_assert(sizeof(T) == 0, "This function should not be called!");
}

在这个例子中,fail_with_compile_error函数被标记为_Noreturn。如果这个函数被调用,那么static_assert会失败,导致编译错误。因此,这个函数永远不会在运行时返回。

6.2 _Noreturn关键字在C++11, 14, 17, 20中的变化和应用

_Noreturn关键字在C++11中首次引入,其目的是为了标记那些不会返回的函数。在C++14, 17, 20中,_Noreturn关键字的语义并没有改变,但是它在这些新的C++标准中的应用变得更加广泛。

例如,在C++20中,我们可以使用_Noreturn关键字来标记那些使用了std::exitstd::abort的函数。这些函数会立即终止程序,因此它们不会返回。

_Noreturn void terminate_with_error(const std::string& message) {
    std::cerr << message << std::endl;
    std::exit(EXIT_FAILURE);
}

在这个例子中,terminate_with_error函数被标记为_Noreturn。这个函数会打印一条错误消息,然后调用std::exit来终止程序。因此,这个函数永远不会返回。

下面是一个表格,总结了_Noreturn关键字在C++11, 14, 17, 20中的应用:

C++版本 _Noreturn的应用
C++11 标记不会返回的函数
C++14 标记不会返回的函数
C++17 标记不会返回的函数
C++20 标记使用了std::exitstd::abort的函数

在C++的各个版本中,_Noreturn关键字的应用都是一致的,都是用来标记那些不会返回的函数。但是在C++20中,我们可以更加广泛地使用_Noreturn关键字,例如标记那些使用了std::exitstd::abort的函数。

下图是一个示意图,展示了一个被标记为_Noreturn的函数在被调用后的行为。你可以看到,这个函数在执行完其代码后,不会返回到调用者,而是结束程序或者转移控制到程序的其他部分。

在这个示意图中,你可以看到一个被标记为_Noreturn的函数在被调用后的行为。这个函数在执行完其代码后,不会返回到调用者,而是结束程序或者转移控制到程序的其他部分。这就是_Noreturn关键字的主要作用。

以上就是_Noreturn关键字在元模板编程和C++各个版本中的应用。希望这些信息能帮助你更好地理解和使用_Noreturn关键字。


结语

在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。

这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。

我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。

目录
相关文章
|
21天前
|
存储 安全 编译器
【C++专栏】C++入门 | auto关键字、范围for、指针空值nullptr
【C++专栏】C++入门 | auto关键字、范围for、指针空值nullptr
27 0
|
1天前
|
存储 C++
c/c++宏定义(函数)
c/c++宏定义(函数)
|
2天前
|
C语言 C++
【C++入门】关键字、命名空间以及输入输出
【C++入门】关键字、命名空间以及输入输出
|
3天前
|
编译器 C++
【C++进阶】引用 & 函数提高
【C++进阶】引用 & 函数提高
|
7天前
|
C++
C++从入门到精通:2.1.2函数和类——深入学习面向对象的编程基础
C++从入门到精通:2.1.2函数和类——深入学习面向对象的编程基础
|
7天前
|
存储 C++
C++从入门到精通:2.1.1函数和类
C++从入门到精通:2.1.1函数和类
|
8天前
|
C++
C++ 访问说明符详解:封装数据,控制访问,提升安全性
C++ 中的访问说明符(public, private, protected)用于控制类成员的可访问性,实现封装,增强数据安全性。public 成员在任何地方都可访问,private 只能在类内部访问,protected 则允许在类及其派生类中访问。封装提供数据安全性、代码维护性和可重用性,通过 setter/getter 方法控制对私有数据的访问。关注公众号 `Let us Coding` 获取更多内容。
23 1
|
15天前
|
机器学习/深度学习 定位技术 C++
c++中常用库函数
c++中常用库函数
38 0
|
16天前
|
算法 搜索推荐 C++
浅谈sort函数底层(一道c++面试的天坑题)
浅谈sort函数底层(一道c++面试的天坑题)
|
18天前
|
编译器 C++
C++ 解引用与函数基础:内存地址、调用方法及声明
C++ 中的解引用允许通过指针访问变量值。使用 `*` 运算符可解引用指针并修改原始变量。注意确保指针有效且不为空,以防止程序崩溃。函数是封装代码的单元,用于执行特定任务。理解函数的声明、定义、参数和返回值是关键。函数重载允许同一名称但不同参数列表的函数存在。关注公众号 `Let us Coding` 获取更多内容。
136 1