有没有办法在单个翻译单元中使用GCC __attribute __((noreturn))和?

在C11中,有一个关键字_Noreturn ,它是一个函数说明符(如inline is),表示函数没有返回 – 它调用exit()或等效函数。 还有一个标题 ,其完整定义是:

7.23 _Noreturn

¶1标题定义宏

 noreturn 

它扩展到_Noreturn

在GNU C(GCC)中,有一个属性__attribute__((noreturn)) ,它基本上执行相同的工作。 一个区别是__attribute__((noreturn))可以出现在函数声明__attribute__((noreturn))之前或之后:

 extern __attribute__((noreturn)) void err_error(const char *format, ...); extern void err_error(const char *format, ...) __attribute__((noreturn)); 

问题是,如果在转换单元(TU)中包含 ,则__attribute__((noreturn))任何后续使用都会映射到__attribute__((_Noreturn)) ,这会导致编译失败,因为属性_Noreturn无法识别(即使关键字被识别为关键字)。 也就是说,据我所知,你不能同时使用这两个系统。

  • 有什么方法可以解决这个问题,除了:

    1. 使用该属性使用的所有代码的大爆炸,或
    2. 使用不完全优雅的_Noreturn关键字?

您可以通过测试__STDC_VERSION__ >= 201112L来检测C11 – 该值由技术勘误1指定,因为标准意外地保留了未完全指定的值:

__STDC_VERSION__整数常量201ymmL178)

178)该宏未在ISO / IEC 9899:1990中规定,在ISO / IEC 9899:1990 / Amd.1:1995中指定为199409L,在ISO / IEC 9899:1999中指定为199901L。 目的是这将保持long int类型的整数常量,随着本国际标准的每次修订而增加。

这可用于在任何一个头文件中调整处理,但如果你有混合的修改和未修改(C11和C99)头文件,我似乎遇到了棘手问题。

  • 是否值得向GCC提交一个错误,要求将__attribute__((_Noreturn))作为__attribute__((noreturn))的同义词 – 这将解决问题。

而是使用__attribute__((__noreturn__))

所有gcc属性都有一个__版本,这样您就可以在系统头文件中使用它们而不会污染用户名空间。

一些平台提供商似乎也没有意识到这个问题。 我最近发现,对于OS X,它们在宏__dead2具有不受保护的版本。

此外,您无法使用__STDC_VERSION__宏可靠地检测C标准版本。 所有gcc和clang版本都有C11的“测试”版本,如果使用-std=c11进行调用而声称C11,而没有完全实现它。 新版本几乎就在那里,但差不多。

这正是关键字_Noreturn而非noreturn 。 不要包含stdnoreturn.h标头,只需使用:

 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define noreturn _Noreturn #elif defined(__GNUC__) #define noreturn __attribute__((noreturn)) #else #define noreturn #endif