【问题标题】:How to use noreturn with function pointer?如何将 noreturn 与函数指针一起使用?
【发布时间】:2015-02-26 09:49:01
【问题描述】:

我正在用 C11 编写引导加载程序。当引导加载程序需要将控制权转移给固件时,它会读取位于预定义内存地址的函数指针并调用它。代码如下所示:

typedef void (FirmwareBootFn)(void);

typedef struct
{
    uint32_t stackPointer;
    FirmwareBootFn* programCounter;
}
FirmwareBootControl;

static FirmwareBootControl g_bootControl __attribute__ ((section (".boot_control")));

void
Firmware_boot( void )
{
    setStackPointer( g_bootControl.stackPointer );
    g_bootControl.programCounter();
}

函数Firmware_boot() 永远不会返回,因此将其声明为noreturn 是有意义的:

#include <stdnoreturn.h>

noreturn void
Firmware_boot( void );

但我还需要将FirmwareBootFn 声明为noreturn,以避免编译器抱怨Firmware_boot() 可能会返回。

我尝试了(可能)noreturntypedef 中的所有排列,但没有任何结果。我也知道该属性不能在typedef 中设置,因为它不是类型的一部分。

有没有办法将我的Firmware_boot() 标记为noreturn 以避免警告(以及没有警告抑制作弊:-))?

【问题讨论】:

  • 我刚刚找到了 gcc 的解决方法:使用 **__builtin_unreachable**() 将代码的特定点标记为“永远不会执行此行”,从而授予 noreturn 属性。尽管这样有效,但它不是可移植的,并且不允许编译器理解(至少在 IMO)g_bootControl.programCounter() 不会返回并应用适当的优化。
  • @MaxP,一个小型测试程序的文档和汇编输出似乎都表明它用于优化。 (如果foo 被声明为_Noreturnbar 不是,foo();bar(); __builtin_unreachable(); 生成等效代码。)
  • 如果您愿意使用扩展程序,请使用attribute。请看我的回答。

标签: c c11 noreturn


【解决方案1】:

C11 中的_Noreturn 只能应用于函数定义或声明。不幸的是,函数不返回的事实不是原型的一部分。

由于您似乎拥有 gcc,因此您可以使用扩展程序

typedef struct
{
    uint32_t stackPointer;
    __attribute__((__noreturn__)) FirmwareBootFn* programCounter;
}
FirmwareBootControl;

将函数指针标记为不返回。不幸的是,似乎没有一种方法可以确保您分配给它的函数确实具有语法上的属性。

【讨论】:

  • 这意味着在 C11 中,如果“noreturn”函数通过指针调用函数来结束自身,则不能调用函数“noreturn”。聪明。
  • @BruceK,我不知道你的“聪明”是什么意思,但是对 C 标准的更改通常是新语义和向后兼容的必要性之间的艰难妥协。特别是,_Noreturn 是一种属性,可以通过在新库和旧可执行文件之间保持二进制兼容来附加到现有函数(如exit)。这不是一项简单的任务。
  • 我了解限制条件。该委员会有 GCC 人员做出贡献,GCC 似乎可以毫无问题地将 _Noreturn 的含义应用于函数指针。这不是火箭科学。程序员是有创造力的人。 _Noreturn 可以被视为可归因于函数指针的属性,或者可以发明一些其他语法,例如 GCC 的语法。 WRT 分配一个返回这样一个指针的函数,好吧,没有语言设计可以防止错误。该属性是一个可能出错的优化提示。
  • @BruceK,我认为您完全错误地理解了委员会的工作方式以及您想要逐步更改标准时的困难所在。当我谈到一项艰巨的任务时,我指的是这种不会使现有 C 库失效的功能的标准化。在大约 10 年的讨论中,在编译器实现者中抨击你最喜欢的敌人而不知道发生了什么,甚至不知道谁在讨论中提出了哪个论点或建议,这简直是可耻的。
猜你喜欢
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 2021-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-05
  • 2019-08-10
相关资源
最近更新 更多