在函数指针赋值中进行强制转换

Casting in function pointer assignment

本文关键字:转换 函数 指针 赋值      更新时间:2023-10-16

以下函数指针分配如何:

exit = (void (*)()) &jump;

不同于:

exit = &jump;

其中 exit 是一个函数指针,定义为:

void (*exit) ();

而"jump"是一个声明为的函数:

void jump();
exit = (void (*)()) &jump;

第一个使用强制铸造。这是危险的,因为它可能会搞砸你的程序,而不会让你知道类型是否不匹配,因为它不会在编译时被捕获。

因此,如果您要这样做:

int func() {return 1;}
auto exit = (void (*)()) &func;

。那会很糟糕。但是,最好执行以下操作:

exit = &jump;

第二个使用编译时类型检查。这更安全,因为编译器将在编译时检查类型。这为您提供了更强大的类型保证。

最好的选择是使用 static_cast<void(*)()> 它是类型安全的,并告诉程序员更多你试图做什么的意图。

auto exit = static_cast<void(*)()>(&func);

如果您有C++,可以尝试以下操作:

如果您不想关心类型,请使用 auto

auto exit = &func

这将确保类型匹配。如果要检查类型,请使用 C++11 及更高版本中存在的<typeinfo>中的typeid().name

std::cout << typeid(exit).name << std::endl;

虽然这通常会为函数提供一些奇怪的输出,但您可能会找到一些可以帮助您的信息,最好的信息是如果两种类型不同。

下面是一个工作示例,显示了运行时使用函数指针强制转换的问题: http://coliru.stacked-crooked.com/a/47f74e8b6f389812

它们非常相似。

在 C 中,如果函数和类型与描述完全一致:

void (*exit) ();
void jump();
exit = (void (*)()) &jump;
exit = &jump;

是相同的。

现在当我更改jump时会发生什么:

int jump();

现在我们正在运行未定义的行为,如果我们在以下之后调用exit,则不会发生错误或警告:

exit = (void (*)()) &jump;

但是在这里我们得到一个类型错误:

exit = &jump;

此外,还可能发生更微妙的差异 - 例如jump可能获得调用约定,因此无法存储在exit中,并且事情会中断。

在C++中,还有另一个微妙的区别。 如果 jump 是一个重载函数,并且 exit 不是原始函数指针(而是std::function<void()>(,则第一个可以编译,而第二个可能不会。 将名称强制转换为函数指针类型可以触发重载解析,否则某些代码将无法工作。

但是,使用static_cast<void(*)()>会更安全。

这两个赋值具有相同的效果。第一种方法&jump"强制转换"到指向不带参数并返回void的函数的指针,但&jump已经是这样了!