为什么当static_cast(ing)一个函数作废*时,编译器的行为会有所不同?

Sou*_*mar 9 c++ function-pointers void-pointers static-cast

以下代码可在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;
}
Run Code Online (Sandbox Code Playgroud)

eer*_*ika 9

函数只能隐式转换为函数指针。甲函数指针不是指针在语言,这仅涉及对象指针字的严格含义。

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


void*保证可以指向功能的系统上(例如POSIX),可以reinterpret_cast改用:

void* p = reinterpret_cast<void*>(func);
Run Code Online (Sandbox Code Playgroud)

但这对于缺乏保证的系统是不可移植的。(我知道没有系统具有C ++编译器并且没有此保证,但这并不意味着该系统不存在)。

标准报价:

[expr.reinterpret.cast]

有条件地支持将函数指针转换为对象指针类型,反之亦然。这种转换的含义是实现定义的,除非如果实现在两个方向都支持转换,则将一种类型的prvalue转换为另一种类型的prvalue,然后再转换回去(可能具有不同的cv限定条件)将产生原始指针值。

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

  • POSIX要求函数指针(代码地址)和对象指针(数据地址)之间具有互转换性,必须使dlsym工作。 (2认同)
  • @eerorika-您正在混合条款。在特定情况下,术语“诊断”在标准中具有标准所要求的特定定义。警告通常会提供标准未规定的其他信息,因为供应商选择这样做是为了对开发人员有所帮助(通常是因为编译器进行的分析超出了标准的要求,因此可以提供其他信息)。对您而言,警告可能是诊断。对于C ++标准,按照标准的定义,不是。 (2认同)
  • @Peter:警告是诊断。defns.diagnostic:“属于实现的输出消息的实现定义子集的消息”。 (2认同)
  • @SoulimaneMammar:标准处理它。它说是否支持转换是由实现定义的。标准对此可以说是最好的(因为可能存在/曾经存在无法进行转换的平台)。但是转换很有可能在当前所有广泛使用的平台上都可以工作(如果平台具有dlsym / GetProcAddress,则应该可以使用)。 (2认同)