为何Clang和GCC对OpenSSL宏不触发旧式类型转换警告?
问题描述
使用-Wold-style-cast编译以下代码:
#include <openssl/evp.h> extern "C" { #define TEST (int)123 } long BIO_ctrl(int bp, int cmd, long larg, void *parg); // 为最小化编译示例添加 int main() { auto example = BIO_pending(123); return TEST; }
执行编译命令g++ foo.cpp -Wold-style-cast -Werror时,仅TEST宏触发错误:
foo.cpp:4:19: error: use of old-style cast to ‘int’ [-Werror=old-style-cast] 4 | #define TEST (int)123 | ^~~ foo.cpp:11:12: note: in expansion of macro ‘TEST’ 11 | return TEST; | ^~~~ cc1plus: all warnings being treated as errors
Clang下也会出现相同错误。但OpenSSL的BIO_pending宏定义为# define BIO_pending(b) (int)BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL),同样使用旧式类型转换,却未触发警告。移除TEST宏后编译成功,将BIO_pending宏定义直接移到foo.cpp中则会触发警告。另外使用distcc时,本地编译正常但远程编译失败,原因是distcc会在本地展开宏后再远程编译,导致警告触发。
疑问:为何仅TEST宏触发警告,OpenSSL宏却无此情况?OpenSSL头文件是否针对该警告做了特殊处理?
原因分析与解答
- 编译器对系统/第三方头文件的默认豁免:GCC和Clang默认会对系统目录(如
/usr/include)下的头文件禁用部分警告,包括-Wold-style-cast。OpenSSL头文件通常安装在系统目录中,因此编译器不会检查其中的旧式转换。而你定义的TEST宏在当前源文件内,属于用户代码范畴,会被编译器严格检查。 - OpenSSL头文件主动抑制警告:OpenSSL的头文件中会通过编译器指令主动关闭相关警告。比如在头文件开头使用
#pragma GCC diagnostic push和#pragma GCC diagnostic ignored "-Wold-style-cast"这类指令,在头文件结束时再恢复警告配置。这样即便头文件不在系统目录,也能避免触发警告。 - distcc编译流程导致的差异:distcc的工作机制是本地完成预处理(展开所有宏)后,将预处理后的代码发送到远程节点编译。此时
BIO_pending宏已被展开为包含旧式转换的代码,这部分代码会被当作用户代码处理,不再享受头文件的警告豁免,因此远程编译时会触发错误。
内容的提问来源于stack exchange,提问作者Sea Erchin
相关产品推荐
相关产品推荐

