__attribute__ noreturn

本文介绍如何在C语言中使用__attribute__((noreturn))属性来标记那些不会返回的函数,如abort()和exit()等。通过这种方式,可以告诉编译器这些函数永远不会返回,从而避免关于未到达的代码路径的错误警告。

This attribute tells the compiler that the function won't ever return, and this can be used to suppress errors about code paths not being reached. The C library functions abort() and exit() are both declared with this attribute:

extern void exit(int)   __attribute__((noreturn));
extern void abort(void) __attribute__((noreturn));

Once tagged this way, the compiler can keep track of paths through the code and suppress errors that won't ever happen due to the flow of control never returning after the function call.

In this example, two nearly-identical C source files refer to an "exitnow()" function that never returns, but without the __attribute__ tag, the compiler issues a warning. The compiler is correct here, because it has no way of knowing that control doesn't return.

$ cat test1.c
extern void exitnow();

int foo(int n)
{
        if ( n > 0 )
	{
                exitnow();
		/* control never reaches this point */
	}
        else
                return 0;
}

$ cc -c -Wall test1.c
test1.c: In function `foo':
test1.c:9: warning: this function may return with or without a value

But when we add __attribute__, the compiler suppresses the spurious warning:

$ cat test2.c
extern void exitnow() __attribute__((noreturn));

int foo(int n)
{
        if ( n > 0 )
                exitnow();
        else
                return 0;
}

$ cc -c -Wall test2.c
no warnings!
<think>我们正在讨论一个关于C语言中_Noreturn关键字的问题。用户想知道在函数`assert_failed`的定义中是否可以去掉`_Noreturn`关键字。 首先,回顾一下这个函数的定义: ```c _Noreturn void assert_failed(char const * const module, int const id); _Noreturn void assert_failed(char const * const module, int const id) { (void)module; // unused parameter (void)id; // unused parameter #ifndef NDEBUG // light up all LEDs GPIOF_AHB->DATA_Bits[LED_GREEN | LED_RED | LED_BLUE] = 0xFFU; // for debugging, hang on in an endless loop... for (;;) { } #endif NVIC_SystemReset(); } ``` 用户的问题是:能否去掉`_Noreturn`? 回答: 1. **可以去掉**:从语法上讲,去掉`_Noreturn`关键字不会影响函数的实际功能。函数本身的行为(点亮LED,死循环,复位)不会改变。 2. **为什么需要`_Noreturn`?** - `_Noreturn`(或C11中的`_Noreturn`)是一个函数说明符,它告诉编译器这个函数不会返回到调用者。这可以帮助编译器进行优化,并避免关于未初始化变量或缺失返回值的警告。 - 在这个函数中,我们确实没有返回:在调试模式下,它进入死循环;在非调试模式下,它调用`NVIC_SystemReset()`(系统复位,不会返回)。所以,这个函数确实不会返回。 3. **去掉的后果**: - 编译器可能会产生警告:如果调用这个函数后还有代码,编译器可能会发出“控制流到达非void函数结尾”的警告(尽管实际上不会执行到函数结尾)。不过在这个函数中,由于有死循环和复位,实际上不会执行到函数结尾,所以没有返回值的问题(函数声明为void,也不需要返回值)。 - 编译器可能无法进行某些优化。例如,它知道函数不会返回,那么在调用这个函数之后的代码就可以被视为不可达代码,从而被优化掉。如果没有`_Noreturn`,编译器可能不会进行这种优化。 4. **建议**: - 保留`_Noreturn`是一个好习惯,因为它更准确地描述了函数的语义,并且有助于编译器的优化和静态分析。 - 如果因为某些原因(例如编译器不支持C11)需要去掉,也可以去掉,但需要确保函数确实不会返回(否则会导致未定义行为)。 5. **兼容性考虑**: - 如果使用的是较老的C标准(如C99),可以使用编译器特定的属性(如gcc的`__attribute__((noreturn))`)来代替`_Noreturn`。 - 在C11之前,我们可以这样写: ```c __attribute__((noreturn)) void assert_failed(...); ``` 因此,结论是:可以去掉,但最好保留。如果编译器不支持C11,则使用编译器特定的属性。 相关问题: 1. `_Noreturn`关键字在C语言中的作用是什么? 2. 如何在不同编译器中实现函数不会返回的语义? 3. 在嵌入式系统中,断言失败后应该采取哪些措施? 4. 如何自定义断言函数以实现不同的调试需求? 5. 为什么在断言失败后有时需要死循环而不是立即复位系统? </think>### 能否去掉 `_Noreturn` 关键字? **可以去掉,但需谨慎处理后续控制流**。以下是详细分析和解决方案: #### 1. **语法可行性** - `_Noreturn` 是 C11 标准引入的函数说明符(非强制关键字) - 其作用是 **向编译器声明函数不会返回调用点**(如死循环、系统复位等) - 移除后不影响编译通过,但需确保函数逻辑满足以下条件: ```c void assert_failed(...) { // 去掉 _Noreturn ... // 必须有终止程序的逻辑(死循环/复位) for(;;); // 或 NVIC_SystemReset(); } ``` #### 2. **移除的必要场景** | 场景 | 处理建议 | 风险 | |---|---|--| | **兼容旧编译器**<br>(如 C99) | 直接移除即可 | 可能触发编译警告 | | **函数可能返回**<br>(如添加错误恢复逻辑) | 必须移除 + 修改控制流 | 否则违反 `_Noreturn` 语义 | | **与第三方库冲突** | 移除 + 添加 `__attribute__((noreturn))`<br>(GCC 扩展) | 编译器兼容性问题 | #### 3. **推荐实现方案** ```c /* 移除 _Noreturn 但保留终止逻辑 */ void assert_failed(char const *module, int id) { (void)module; (void)id; // 消除未使用参数警告 #ifndef NDEBUG // 调试模式:LED报警 + 死循环 GPIOF_AHB->DATA_Bits[LED_ALL] = 0xFFU; while(1); // 明确永不返回 #else // 发布模式:直接复位 NVIC_SystemReset(); #endif } ``` **关键点**: - 在调试分支添加 `while(1);` **显式声明不返回**[^2] - 使用 `NVIC_SystemReset()` 确保复位后不返回(ARM Cortex-M 特性) #### 4. **编译器兼容性处理** ```c /* 多编译器支持方案 */ #if defined(__GNUC__) __attribute__((noreturn)) #elif defined(__ICCARM__) __noreturn #elif defined(__CC_ARM) __attribute__((noreturn)) #endif void assert_failed(...) { ... } ``` ### 相关问题 1. `_Noreturn` 关键字在资源受限嵌入式系统中是否有性能优势? 2. 如何实现跨平台(ARM/IAR/GCC)的断言终止函数? 3. 系统复位 `NVIC_SystemReset()` 与软件复位有何区别? 4. 为什么某些嵌入式标准要求断言失败后必须死循环而非立即复位? 5. C11 标准中 `_Noreturn` 与 C++ `[[noreturn]]` 的兼容性如何解决? [^1]: C11 标准断言机制 [^2]: STM32 断言最佳实践
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值