在C和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有条件地支持将函数指针转换为对象指针类型(反之亦然)。 这种转换的含义是实现定义的,除非实现支持两个方向的转换,将一种类型的prvalue转换为另一种类型并返回,可能具有不同的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引入了条件支持function的概念,并使用它来使标准与现有实践相适应。 现在,编译器应该拒绝尝试进行此类转换的程序,或者它应该遵守给定的有限约束。

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

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

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

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

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

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

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