考虑使用
-Wold-style-cast
编译以下代码
#include <openssl/evp.h>
extern "C" {
#define TEST (int)123
}
long BIO_ctrl(int bp, int cmd, long larg, void *parg); // added for the example to compile minimally.
int main() {
auto example = BIO_pending(123);
return TEST;
}
https://godbolt.org/z/Mdodc58z7
如果我们调用文件
foo.cpp
并使用 g++ foo.cpp -Wold-style-cast -Werror
进行编译,则会失败并出现以下输出的警告:
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 上也失败了。
为什么我们只收到使用
TEST
的警告,而没有收到 BIO_pending
当它们都使用旧式转换时?
注意openssl宏定义如下:
# define BIO_pending(b) (int)BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
我认为它可能是在
extern "C"
块中定义的,但显然不是。
注意,去掉
TEST
的使用就意味着编译成功。
另外,将 BIO_pending
的定义放入 foo.cpp
中也会导致发出警告。
openssl 和此类标头是否以某种方式为这些警告内置了异常?
当我注意到使用 distcc 的构建无法远程完成但在本地编译时,我发现了这一点。 Distcc 在远程编译之前会在本地扩展宏,因此将宏移出标头会导致出现警告并导致编译失败。
基本上,取决于上下文。
考虑在
BIO_pending
中定义的 OpenSSL
宏为:
# define BIO_pending(b) (int)BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
在此上下文中,
macro
用于调用函数,类型转换是 BIO_pending
函数工作方式的一个组成部分。因此,编译器不会针对这种情况发出旧式警告,因为它们认为类型转换是函数接口的一部分,而不是旧式的不安全使用。
另一方面,代码中定义的
TEST
宏并不与特定的OpenSSL
函数或操作关联;它只是表达式中的类型转换。由于这种类型转换被认为是一种旧式做法,并且可能存在潜在危险,因此编译器在遇到这种旧式用法时会发出警告。
OpenSSL
macros
和代码定义的 macros
之间处理旧式警告的差异是由于 macros
的性质以及它们在每种上下文中的使用方式造成的。