是否已定义使用在比较中被转换为其他类型的函数指针?

时间:2017-12-01 16:17:20

标签: c++ casting function-pointers

不能直接比较不同类型的函数指针:

#include <iomanip>
#include <iostream>

int foo() { return 0; }
void bar(int) {}

int main()
{
    // Doesn't compile, the comparison is not allowed
    std::cout << std::boolalpha << (&foo == &bar) << std::endl;
    return 0;
}

但是,如果将一个函数指针强制转换为另一个函数指针的类型,是否定义了将该投射的结果与其他函数指针进行比较的行为?

#include <iomanip>
#include <iostream>

int foo() { return 0; }
void bar(int) {}

int main()
{
    auto cast_ptr = reinterpret_cast<decltype(&bar)>(&foo);

    // Printed "false" when I tried it, but is this guaranteed?
    std::cout << std::boolalpha << (cast_ptr == &bar) << std::endl;
}

如果两个运算符都被强制转换为常见但不同的类型怎么样?

#include <iomanip>
#include <iostream>

int foo() { return 0; }
void bar(int) {}

int main()
{
    using cast_type = void(*)();
    auto cast_foo = reinterpret_cast<cast_type>(&foo);
    auto cast_bar = reinterpret_cast<cast_type>(&bar);

    // Also printed "false" when I tried it, but is this guaranteed?
    std::cout << std::boolalpha << (cast_foo == cast_bar) << std::endl;
}

我理解函数指针比较相等,当且仅当它们都指向nullptr或同一函数时。对我来说不清楚的是,是否允许使用在比较中被转换为另一个函数指针类型的函数指针。

上下文

我正在维护一个带有c兼容API的c ++库。该库记录对API函数的每次调用。在运行时有选择地禁用某些功能的日志记录会很有用。就可用性而言,当前最好的提议是提供一个新的API函数,该函数将API函数的指针作为参数,该函数的日志记录应该被抑制。由于API函数具有不同的参数,因此这些指针将具有不同的类型,并且需要转换为常见的函数指针类型,例如void(*)()。然后,在记录API函数调用之前,将搜索void(*)()的容器以查找被调用函数的地址,以便知道是否记录该调用。

1 个答案:

答案 0 :(得分:0)

来自[expr.reinterpret.cast]

  

函数指针可以显式转换为不同类型的函数指针。 [...]除了将“指向System.out.println("\f"); 的指针”的prvalue转换为“指向T1的指针”(其中T2T1是函数类型)并且返回其原始类型会产生原始指针值,这种指针转换的结果是未指定的。

未指定铸造函数指针是否相等。

  

指针可以显式转换为足以容纳它的任何整数类型。映射函数是实现定义的。

因此,转换为T2或其他合适的类型是自然的选择,前提是实现不会使用某种古怪的转换。

来自GCC's documentation

  

如果指针表示大于整数类型,从指针到整数的转换会丢弃最高有效位,如果指针表示小于整数类型,则签名扩展 1 ,否则位没有变化。

AKA理智的转换。这可能是我在大多数情况下会发现的,我敢打赌。

[1] GCC的未来版本可以零扩展,或使用目标定义的ptr_extend模式。不要依赖签名扩展。