背景
注意:这对于问题来说并不重要
我有一些宏,它们充当属性的更通用版本,我将它们附加到函数中。根据编译器和编译器版本,它们将扩展为属性(例如__attribute__((nonnull))
),或警告(例如_Pragma("message \"nonnull attribute unavailable\"")
)。由于属性宏可以按任何顺序排列,这可能导致它们混杂在一起(例如警告属性属性警告警告)。
结果是我可以得到如下代码:
样本
#pragma message "one"
__attribute__((cold))
#pragma message "two"
__attribute__((noreturn))
#pragma message "three"
void test(void);
问题
运行后clang
,此示例代码编译完美,并按预期打印三条消息。
input.c:1:9: warning: one [-W#pragma-messages]
#pragma message "one"
^
input.c:3:9: warning: two [-W#pragma-messages]
#pragma message "two"
^
input.c:5:9: warning: three [-W#pragma-messages]
#pragma message "three"
^
但是运行时gcc
,第二个出现错误#pragma
。如果我将其注释掉,第三个又会出现错误#pragma
。
input.c:1:9: note: ‘#pragma message: one’
1 | #pragma message "one"
| ^~~~~~~
input.c:3:9: error: expected identifier or ‘(’ before ‘#pragma’
3 | #pragma message "two"
| ^~~~~~~
input.c:1:9: note: ‘#pragma message: one’
1 | #pragma message "one"
| ^~~~~~~
input.c:5:9: error: expected identifier or ‘(’ before ‘#pragma’
5 | #pragma message "three"
| ^~~~~~~
经过实验,似乎在 之后gcc
不接受任何指令。#pragma
__attribute__
可重现的示例
取消注释#pragma
会导致 GCC v11.4.0 上出现可重现的错误
__attribute__((nonnull))
// #pragma message "this is an error"
void test(void);
问题
是否有任何修复或解决方案允许我将#pragma
和__attribute__
指令混合在一起gcc
,就像clang
允许一样?
我尝试了许多不同的组合,它们都产生了您所看到的结果。
这可能是由于
gcc
和clang
解析的方式不同。clang
已完全集成预处理器。 对于gcc
,它是一个单独的过程/程序。因此,就我所知,没有直接的解决方案。
您没有指定宏是如何有条件生成的,但我猜一下。您有类似于
autoconf
探测系统并生成宏的东西(例如config.h
)。如果您[只是]想对不受支持的属性发出警告/错误,可能存在一种解决方法。
这有点像黑客行为,但是......
用 进行编译
-DHAVE_INLINE
可以顺利编译。编译时无需
-DHAVE_INLINE
生成:它甚至可以更简单: