繁体   English   中英

在 C 和 C++ 中的函数指针和对象指针之间转换

[英]Casts between pointer-to-function and pointer-to-object in C and C++

我对以下内容有误吗?

C++ 标准说函数指针和对象指针(和返回)之间的转换是条件支持的,实现定义的语义,而所有 C 标准都说这在所有情况下都是非法的,对吧?

void foo() {}

int main(void)
{
    void (*fp)() = foo;
    void* ptr = (void*)fp;
    return 0;
}

ISO/IEC 14882:2011

5.2.10 重新解释转换 [expr.reinterpret.cast]

8 有条件地支持将 function 指针转换为 object 指针类型,反之亦然。 这种转换的含义是实现定义的,除非实现支持双向转换,将一种类型的纯右值转换为另一种类型并返回,可能具有不同的 cvqualification,应产生原始指针值。

我现在在 C 标准中找不到任何关于它的信息......

你是对的,C(99)标准没有说明从指针到函数到指针到对象的转换,因此它是未定义的行为。 *


但请注意,它确实定义了指针到函数类型之间的行为。

  • 在C ++ 03中,这种转换是非法的(不是UB)。 编译器应该发出诊断。 Unix系统上的许多编译器都没有发出诊断信息。 这基本上是标准,POSIX和C ++之间的冲突。
  • 在C ++ 11中,这种转换是“有条件支持的”。 如果系统支持此类转换,则无需诊断; 没有什么可以诊断的。
  • 在C中,这种转换正式是未定义的行为,因此不需要诊断。 如果系统碰巧做了“正确”的事情,那么这就是实现UB的一种方式。
  • 在C99中,这又是UB。 但是,该标准还将此类转换列为该语言的“常见扩展”之一:

    J.5.7函数指针强制转换
    指向对象或void的指针可以转换为指向函数的指针,允许将数据作为函数调用(6.5.4)。
    指向函数的指针可以转换为指向对象的指针或void,允许检查或修改函数(例如,通过调试器)(6.5.4)。

在所有C标准中,没有定义指针到函数和指向对象的指针之间的转换,在C ++ 11之前的C ++中,不允许转换,编译器必须给出错误,但有些编译器接受了转换为C和向后兼容性因为对动态加载的库访问(例如dlsym POSIX函数强制使用它)很有用。 C ++ 11引入了有条件支持的功能的概念,用它来使标准适应现有的实践。 现在,编译器应该拒绝尝试进行此类转换的程序,或者它应该遵守给定的有限约束。

虽然演员的行为不是由标准的“核心”定义的,但在C99基本原理文件(6.3.2.3, 指针 )中明确将此案例描述为无效:

关于函数的指针没有任何说法,这可能与对象指针和/或整数不相称。

即使使用显式强制转换,将函数指针转换为对象指针或指向void的指针也是无效的,反之亦然。

由于它可能有用,它在标准的附件J中也被称为“公共扩展”(C11标准J.5.7, 函数指针转换 ):

指向对象或void的指针可以转换为指向函数的指针,允许将数据作为函数调用(6.5.4)。

指向函数的指针可以转换为指向对象的指针或void ,允许检查或修改函数(例如,通过调试器)(6.5.4)。

将其描述为扩展意味着这不是标准要求的一部分(但不需要,任何明确行为的遗漏就足够了)。

POSIX 标准规定:

2.12.3指针类型
所有 function 指针类型应具有与指向 void 的类型指针相同的表示。 将 function 指针转换为 void * 不应改变表示。 可以使用显式转换将由此类转换产生的 void * 值转换回原始 function 指针类型,而不会丢失信息。

注意:ISO C 标准不要求这样做,但符合 POSIX 要求。

这个要求最终意味着任何想要能够支持 POSIX 的 C 或 C++ 编译器都将支持这种类型的转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM