【问题标题】:Why do compilers behave differently when static_cast(ing) a function to void*?为什么当 static_cast(ing) 一个函数为 void* 时编译器的行为会有所不同?
【发布时间】:2019-08-14 14:52:58
【问题描述】:

以下代码在 VSC++2017 中编译没有任何错误,在 gcc 7.3.0 中无法编译 (error: invalid static_cast from type ‘int(int)’ to type ‘void*’ void* p = static_cast<void*>(func))

#include <iostream>

int func(int x) { return 2 * x; }

int main() {

    void* p = static_cast<void*>(func);
    return 0;
}

【问题讨论】:

  • 函数指针有点奇怪。我必须参加标准潜水,但我很确定 MSVC 正在为了他们自己的邪恶目的而改变标准。
  • @user4581301 不是真的 - 另一个问题是关于 C 的,并且语言可能存在差异......
  • 虽然函数指针与对象指针是不同的动物,但大多数不兼容发生在sizeof() 两者不同时。如果它们相同,您通常可以安全地来回转换为void*。即便如此,虽然它可以工作,但它不是便携的,只是最好避免的事情之一。

标签: c++ function-pointers void-pointers static-cast


【解决方案1】:

函数只能隐式转换为函数指针。 函数指针并不是语言中严格意义上的指针,它只指指向对象的指针。

函数指针无法使用static_cast 转换为void*。所示程序格式错误。如果编译器没有发出警告,则它不符合标准。未能编译格式错误的程序并不违反标准。


在保证void* 能够指向函数的系统上(例如POSIX),您可以改用reinterpret_cast

void* p = reinterpret_cast<void*>(func);

但这不适用于缺乏保证的系统。 (我知道没有一个系统有 C++ 编译器并且没有这个保证,但这并不意味着这样的系统不存在)。

标准报价:

[expr.reinterpret.cast]

有条件地支持将函数指针转换为对象指针类型或反之亦然。意义 这种转换是实现定义的,除非实现支持两种转换 方向,将一种类型的纯右值转换为另一种类型并返回,可能具有不同的 cv 限定, 应产生原始指针值。

请注意,这种条件支持不会扩展到指向成员函数的指针。指向成员函数的指针不是函数指针。

【讨论】:

  • POSIX 需要函数指针(代码地址)和对象指针(数据地址)之间的相互转换,必须让dlsym 工作。
  • @Peter 如果程序格式不正确,该标准要求进行诊断(除非另有说明)。所示程序格式错误。需要进行诊断。警告是一种诊断形式,发出警告就足以符合标准。缺乏诊断是违反标准的。
  • @eerorika - 你混淆了术语。术语“诊断”在标准中具有特定定义,如标准在特定情况下所要求的那样。警告通常提供标准未强制要求的附加信息,因为供应商选择这样做,作为对开发人员的帮助(通常是因为编译器所做的分析比标准要求的更多,因此可以提供附加信息)。对您来说,警告可能是一种诊断。对于 C++ 标准,根据标准中的定义,它不是。
  • @Peter:警告就是诊断。 defns.diagnostic: "属于实现输出消息的实现定义子集的消息"。
  • @SoulimaneMammar:标准处理它。它说它是实现定义是否支持转换。这是标准可以说的最好的(因为可能有/曾经有平台,无法进行转换)。但是这种转换很可能在所有当前广泛使用的平台上都有效(如果平台有 dlsym/GetProcAddress,它应该可以工作)。
猜你喜欢
  • 2018-11-18
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2016-08-15
  • 1970-01-01
  • 2012-08-28
  • 1970-01-01
相关资源
最近更新 更多