为什么 clang 和 gcc 不会对此 openssl 宏产生强制转换警告,而是会产生其他警告?

问题描述 投票:0回答:1

考虑使用

-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 在远程编译之前会在本地扩展宏,因此将宏移出标头会导致出现警告并导致编译失败。

c++ gcc macros clang preprocessor
1个回答
0
投票

基本上,取决于上下文。

考虑在

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
的性质以及它们在每种上下文中的使用方式造成的。

© www.soinside.com 2019 - 2024. All rights reserved.