c++ - C++-17:将函数指针转换为具有不同参数指针类型的函数
问题描述
我有一个遗留的 C-API,它为异步操作提供回调。由于这个库需要许多编译器标志,充满了宏,并且包含头文件时会产生大量警告,所以我决定为这个库创建一个封装专有 C 库的包装器。
但是由于这个库是异步的,它提供了回调函数。问题是,回调需要一个指向 struct ( X_leg
) 的指针。但是由于这个结构是旧 API 的一部分,我不想包含这个结构,所以我决定创建一个具有相同布局的结构X_wrp
。在 main() 中,我确保两个结构的大小相等。
我现在的问题是:将reinterpret_cast
type 的包装函数指针指向具有 typefunc_wrp
的遗留函数指针是否安全func_leg
?还是 C++17 中未定义的行为?
我有以下最小的工作示例:
#include <iostream>
#include <cstdint>
//begin of wrapper decls
struct X_wrp {
std::uint32_t member;
};
using func_wrp = void (*)(const X_wrp* arg);
void caller_wrp(func_wrp func);
//end of wrapper decls
//Legacy C-Code
typedef struct {
std::uint32_t member;
} X_leg;
typedef void (*func_leg)(const X_leg* arg);
void caller_leg(func_leg func) {
static X_leg inst{10};
func(&inst);
}
//End of Legacy C-Code
void callback(const X_wrp* arg) {
std::cout << arg->member << std::endl;
}
int main() {
static_assert(sizeof(X_leg)==sizeof(X_wrp));//ensures that there is no oops
caller_wrp(callback);
return EXIT_SUCCESS;
}
//begin of wrapper implementations
void caller_wrp(func_wrp func) {
caller_leg(reinterpret_cast<func_leg>(func)); //is this cast safe?
}
//end of wrapper implementations
解决方案
不,这是不安全的,并且在[expr.call]/6中被明确称为未定义行为
通过函数类型与被调用函数定义的函数类型不同的表达式调用函数会导致未定义的行为。
reinterpret_cast
这在有关函数指针转换 的文档中也得到了加强[expr.reinterpret.cast]/6
函数指针可以显式转换为不同类型的函数指针。[注:通过指向与函数定义中使用的类型不同的函数类型([dcl.fct])的指针调用函数的效果是未定义的([expr.call])。— 尾注] 除了将类型为“指向 T1 的指针”的纯右值转换为类型“指向 T2 的指针”(其中 T1 和 T2 是函数类型)并返回其原始类型会产生原始指针值,这样的结果未指定指针转换。[ 注意:有关指针转换的更多详细信息,另请参阅 [conv.ptr]。——尾注]
推荐阅读
- python - Python .exe 应用程序 windows 7 错误 api-ms-win-crt-runtime-l1-1-0-dll
- node.js - 如何将数据推送到nodejs中对象数组的现有元素中?
- javascript - 更改文本并添加过渡以使其平滑
- reactjs - 如何声明具有正常语法的函数并使用子级与 TS 反应?
- python - 检查输入时出错:预期 input_12 有 4 个维度,但得到的数组具有形状(无、无、无、无、无)
- linq - Linq 加入一个案例
- rust - 如何将 -rlink 参数传递给链接器?
- javascript - React i18n 语言对象映射
- node.js - TypeORM 连接与连接表中数据条件的关系
- java - 尝试使用 String.join 打印,但它不起作用