C++-17:将函数指针转换为具有不同参数指针类型的函数
C++-17: cast function pointer to function with different argument pointer type
我有一个遗留的 C-API,它为异步操作提供回调。
由于这个库需要很多编译器标志,充满了宏,并且包含头文件时会生成大量警告,所以我决定为这个库创建一个封装专有 C 库的包装器。
但是由于这个库是异步的,所以它提供了回调函数。
问题是,回调需要一个指向结构的指针 (X_leg
)。
但是由于这个结构是旧 API 的一部分,我不想包含这个结构,
我决定创建一个具有相同布局 X_wrp
的结构。
在 main() 中,我确保两个结构的大小相等。
我现在的问题是:
reinterpret_cast
类型 func_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
中被明确称为未定义行为
Calling a function through an expression whose function type is different from the function type of the called function's definition results in undefined behavior.
reinterpret_cast
关于函数指针转换的文档也加强了这一点 [expr.reinterpret.cast]/6
A function pointer can be explicitly converted to a function pointer of a different type. [ Note: The effect of calling a function through a pointer to a function type ([dcl.fct]) that is not the same as the type used in the definition of the function is undefined ([expr.call]). — end note ] Except that converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [ Note: See also [conv.ptr] for more details of pointer conversions. — end note ]
我有一个遗留的 C-API,它为异步操作提供回调。 由于这个库需要很多编译器标志,充满了宏,并且包含头文件时会生成大量警告,所以我决定为这个库创建一个封装专有 C 库的包装器。
但是由于这个库是异步的,所以它提供了回调函数。
问题是,回调需要一个指向结构的指针 (X_leg
)。
但是由于这个结构是旧 API 的一部分,我不想包含这个结构,
我决定创建一个具有相同布局 X_wrp
的结构。
在 main() 中,我确保两个结构的大小相等。
我现在的问题是:
reinterpret_cast
类型 func_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
中被明确称为未定义行为Calling a function through an expression whose function type is different from the function type of the called function's definition results in undefined behavior.
reinterpret_cast
关于函数指针转换的文档也加强了这一点 [expr.reinterpret.cast]/6
A function pointer can be explicitly converted to a function pointer of a different type. [ Note: The effect of calling a function through a pointer to a function type ([dcl.fct]) that is not the same as the type used in the definition of the function is undefined ([expr.call]). — end note ] Except that converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified. [ Note: See also [conv.ptr] for more details of pointer conversions. — end note ]