有没有办法在一个翻译单元中理智地使用 GCC __attribute__((noreturn)) 和 <stdnoreturn.h>?
Is there a way to use GCC __attribute__((noreturn)) and <stdnoreturn.h> sanely in a single translation unit?
在 C11 中,有一个关键字 _Noreturn
,它是一个函数说明符(就像 inline
一样),表示函数不 return — 它调用 exit()
或同等学历。还有一个header,<stdnoreturn.h>
,完整的定义是:
7.23 _Noreturn <stdnoreturn.h>
¶1 The header <stdnoreturn.h>
defines the macro
noreturn
which expands to _Noreturn
.
在 GNU C (GCC) 中,有一个属性 __attribute__((noreturn))
基本上完成相同的工作。一个区别是 __attribute__((noreturn))
可以出现在函数声明符之前或之后:
extern __attribute__((noreturn)) void err_error(const char *format, ...);
extern void err_error(const char *format, ...) __attribute__((noreturn));
问题是,如果您在翻译单元 (TU) 中包含 <stdnoreturn.h>
,任何后续使用的 __attribute__((noreturn))
都会映射到 __attribute__((_Noreturn))
,这会导致编译失败,因为属性 _Noreturn
未被识别(即使关键字被识别为关键字)。也就是说,据我所知,您不能同时使用这两个系统。
有没有其他办法解决这个问题:
- a big-bang迁移所有使用属性的代码使用
<stdnoreturn.h>
,或者
- 使用 less-than-entirely-graceful
_Noreturn
关键字?
您可以通过测试 __STDC_VERSION__ >= 201112L
来检测 C11 — 该值由技术勘误 1 指定,因为标准意外地留下了不完整指定的值:
__STDC_VERSION__
The integer constant 201ymmL.178)
178) This macro was not specified in ISO/IEC 9899:1990 and was specified as 199409L in
ISO/IEC 9899:1990/Amd.1:1995 and as 199901L in ISO/IEC 9899:1999. The intention is that this
will remain an integer constant of type long int
that is increased with each revision of this
International Standard.
这可用于在任何一个 header 文件中对处理进行条件处理,但如果您混合使用修改过的和未修改的(C11 和 C99)headers,我似乎是 运行 变成 <stdnoreturn.h>
的棘手问题。
- 是否值得向 GCC 提交错误以请求将
__attribute__((_Noreturn))
变成 __attribute__((noreturn))
的同义词 — 这将解决问题。
改用__attribute__((__noreturn__))
。
所有 gcc 属性都有一个 __
版本,这样您就可以在系统头文件中合理地使用它们而不会污染用户名 space。
一些平台提供商似乎也没有意识到这个问题。我最近发现,对于 OS X,他们在宏 __dead2
.
中有未受保护的版本
此外,您无法使用 __STDC_VERSION__
宏可靠地检测 C 标准版本。所有具有 C11 的 "test" 版本的 gcc 和 clang 版本如果使用 -std=c11
调用则声明 C11 而没有完全实现它。较新的版本几乎已经存在,但只是差不多。
这正是关键字是 _Noreturn
而不是 noreturn
的原因。不要包含 stdnoreturn.h
header,只需使用:
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define noreturn _Noreturn
#elif defined(__GNUC__)
#define noreturn __attribute__((__noreturn__))
#else
#define noreturn
#endif
在 C11 中,有一个关键字 _Noreturn
,它是一个函数说明符(就像 inline
一样),表示函数不 return — 它调用 exit()
或同等学历。还有一个header,<stdnoreturn.h>
,完整的定义是:
7.23
_Noreturn <stdnoreturn.h>
¶1 The header
<stdnoreturn.h>
defines the macronoreturn
which expands to
_Noreturn
.
在 GNU C (GCC) 中,有一个属性 __attribute__((noreturn))
基本上完成相同的工作。一个区别是 __attribute__((noreturn))
可以出现在函数声明符之前或之后:
extern __attribute__((noreturn)) void err_error(const char *format, ...);
extern void err_error(const char *format, ...) __attribute__((noreturn));
问题是,如果您在翻译单元 (TU) 中包含 <stdnoreturn.h>
,任何后续使用的 __attribute__((noreturn))
都会映射到 __attribute__((_Noreturn))
,这会导致编译失败,因为属性 _Noreturn
未被识别(即使关键字被识别为关键字)。也就是说,据我所知,您不能同时使用这两个系统。
有没有其他办法解决这个问题:
- a big-bang迁移所有使用属性的代码使用
<stdnoreturn.h>
,或者 - 使用 less-than-entirely-graceful
_Noreturn
关键字?
- a big-bang迁移所有使用属性的代码使用
您可以通过测试 __STDC_VERSION__ >= 201112L
来检测 C11 — 该值由技术勘误 1 指定,因为标准意外地留下了不完整指定的值:
__STDC_VERSION__
The integer constant 201ymmL.178)178) This macro was not specified in ISO/IEC 9899:1990 and was specified as 199409L in ISO/IEC 9899:1990/Amd.1:1995 and as 199901L in ISO/IEC 9899:1999. The intention is that this will remain an integer constant of type
long int
that is increased with each revision of this International Standard.
这可用于在任何一个 header 文件中对处理进行条件处理,但如果您混合使用修改过的和未修改的(C11 和 C99)headers,我似乎是 运行 变成 <stdnoreturn.h>
的棘手问题。
- 是否值得向 GCC 提交错误以请求将
__attribute__((_Noreturn))
变成__attribute__((noreturn))
的同义词 — 这将解决问题。
改用__attribute__((__noreturn__))
。
所有 gcc 属性都有一个 __
版本,这样您就可以在系统头文件中合理地使用它们而不会污染用户名 space。
一些平台提供商似乎也没有意识到这个问题。我最近发现,对于 OS X,他们在宏 __dead2
.
此外,您无法使用 __STDC_VERSION__
宏可靠地检测 C 标准版本。所有具有 C11 的 "test" 版本的 gcc 和 clang 版本如果使用 -std=c11
调用则声明 C11 而没有完全实现它。较新的版本几乎已经存在,但只是差不多。
这正是关键字是 _Noreturn
而不是 noreturn
的原因。不要包含 stdnoreturn.h
header,只需使用:
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define noreturn _Noreturn
#elif defined(__GNUC__)
#define noreturn __attribute__((__noreturn__))
#else
#define noreturn
#endif