14

我对以下内容有误吗?

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 有条件地支持将函数指针转换为对象指针类型或反之亦然。这种转换的含义是实现定义的,除非实现支持双向转换,将一种类型的纯右值转换为另一种类型并返回,可能具有不同的 cvqualification,应产生原始指针值。

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

4

4 回答 4

10

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

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

于 2013-01-02T16:59:50.437 回答
9

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


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

于 2013-01-02T16:26:05.470 回答
5

在所有 C 标准中,没有定义指针到函数和指针到对象之间的转换,在 C++11 之前的 C++ 中,不允许转换并且编译器必须给出错误,但是有些编译器接受C 和向后兼容性的转换,因为对于动态加载的库访问(例如dlsymPOSIX 函数要求使用它)等事情很有用。C++11 引入了条件支持特性的概念,并使用它来使标准与现有实践相适应。现在编译器应该拒绝尝试进行这种转换的程序,或者它应该尊重给定的有限约束。

于 2013-01-02T16:35:24.633 回答
5

尽管强制转换的行为没有由标准的“核心”定义,但这种情况在 C99 基本原理文档(6.3.2.3,指针)中被明确描述为无效:

关于指向函数的指针什么也没说,这可能与对象指针和/或整数不相称。

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

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

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

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

将其描述为扩展意味着这不是标准要求的一部分(但它不是必需的,省略任何显式行为就足够了)。

于 2013-01-02T16:53:55.763 回答