将指向函数的指针转换为指向函数类型的不同指针的结果

Result of converting a pointer to function to different pointer to function type

本文关键字:函数 指针 结果 转换 类型      更新时间:2023-10-16

(5.2.10/6( C++03 指向函数的指针可以显式转换为指向不同类型的函数的指针。调用函数的效果 通过指向与 不同的函数类型 (8.3.5( 的指针 函数定义中使用的类型未定义。除了 将类型为"指向 T1 的指针"的右值转换为"指针"类型 到 T2"(其中 T1 和 T2 是函数类型(并返回其原始状态 类型生成原始指针值,即此类指针的结果 未指定转换。[注:详见4.10 指针转换。

以下是我正在尝试做的事情,虽然很明显,将fp1转换为fp2的结果将产生原始指针,但同时标准中的措辞会"The result of such a pointer conversion is unspecified" 这是什么意思?

int f() { return 42; }
int main()
{
    void(*fp1)() = reinterpret_cast<void(*)()>(f);
    int(*fp2)() = reinterpret_cast<int(*)()>(fp1);
    // Safe to call the function ?
    fp2();
}

您误读了标准,"未指定"部分仅适用于其他转换:

除 [特殊情况] 外,未指定此类指针转换的结果。

该 [特殊情况] 是您转换回原始函数指针类型的一种,如您的示例所示。在这种特殊情况下,转换会生成原始指针值,因此可以像在示例中一样使用它。

仅对于其他转换,结果是未指定的。

是的,它是安全的。
reinterpret_cast只允许您将一个指针强制转换为另一个指针,但它不保证任何安全性,并且使用此类指针的结果未指定,除非将其类型转换回其原始类型。

提到的标准引号指定,如果将一种类型的函数指针类型转换为另一种类型并尝试通过它调用函数,则结果是未定义的。

然而
reinterpret_cast保证,如果将类型转换的指针转换回原始类型,则指针的格式正确。

您的代码尝试执行第二个操作,因此它是安全的。

是的,你很安全。您正在做的事情包含在"除了转换..."箱。

调用它的原因是允许您通过其他类型的函数指针传递函数指针。因此,您可以定义如下内容:

enum CallbackType {
    eFuncPtrVoidReturningVoid,
    eFuncPtrVoidReturningInt,
    // ... more as needed ...
};
class CallbackRecord
{
public:
    CallbackRecord(void (*cb)()): cbType(eFuncPtrVoidReturningVoid), cbFunc(cb) 
        {}
    CallbackRecord(int (*cb)()): cbType(eFuncPtrVoidReturningInt), 
        cbFunc(reinterpret_cast<void (*)()>(cb)) {}
    void operator()() const;
protected:
    CallbackType cbType;
    void (*cbFunc)();
};
void CallbackRecord::operator()() const
{
    switch(cbType)
    {
    case eFuncPtrVoidReturningVoid:
        (*cbFunc)();
        break;
    case eFuncPtrVoidReturningInt:
        while((*reinterpret_cast<int (*)()>(cbFunc))())
            ;
        break;
    }
}

虽然你可以说"让所有回调都返回int",但如果回调类型的数量超过两个,这将要求你为不符合调用约定的任何内容编写包装器。 允许这些函数指针类型转换为您提供了支持多种回调类型的替代方法,并使我们不需要将CallbackRecord转换为模板。它还允许子类化或封送处理来替换上面的 switch 语句,而无需使用 virtual 方法。