【问题标题】:Are two function pointers to the same function always equal?指向同一个函数的两个函数指针总是相等的吗?
【发布时间】:2013-10-08 16:07:20
【问题描述】:

C++ 标准是否保证指向函数的两个指针总是比较相等?我知道这对于非内联函数通常是正确的。但是如果有一个内联函数并且指向该函数的指针是在两个独立的编译单元中创建的,那么链接器会合并两个实例化,还是允许发出重复的函数?

如果上面的答案是“它们是相等的”:如果有一个带有内联函数的公共头文件,并且主程序和动态加载的插件(共享对象/DLL)都创建一个指针,这仍然成立吗?函数?

【问题讨论】:

    标签: c++ function-pointers


    【解决方案1】:

    C++11 标准的第 5.10/1 节说:

    两个相同类型的指针比较相等当且仅当它们是 都为null,都指向同一个函数,或者都代表同一个 地址

    相同inline 函数的两个副本仍然是相同的函数。从实现的角度来看,编译器将在每个翻译单元中生成函数的副本,但链接器随后会丢弃其中一个副本,因此只剩下一个。

    通过获取函数的地址,您可以防止它被内联(与 inline 不同,后者更多是为了避免违反单一定义规则)。

    DLL 不在标准范围之内,但二进制映像中只会保留一份函数副本,因此从 DLL 获取函数地址(例如GetProcAddress)将获得与 DLL 内代码相同的函数指针。

    【讨论】:

    • 您的最后一点仅在同一进程的域中是正确的。如果 DLL 被更多进程“共享”,则该函数可能在不同进程中具有不同的地址(并且 DLL 中的代码将看到不同的地址,具体取决于调用它的进程,每个查看的地址也不同)。此外,这些“不同的地址”可能是同一物理资源的“图像”(因此将保持共享),而“状态”(数据段)将保持不同。
    • 我认为你的措辞很混乱。关键是,在获取函数的地址时,您永远不会得到“内联”副本。您将获得 外部可见的函数定义。这甚至可以用来强制实例化一个函数模板,即使它没有以其他方式使用。
    • @sehe:这是一个合理的近似值,但不一定正确。想象一个带有“尾部内联”的编译器——如果函数的最后一条语句是return f(),则内联f() 的整个主体,并且可能放一个小跳转来跳过一些序言代码。您现在有一个内联函数 f 也可以独立调用。函数指针可以指向该内联副本。该标准通过不详细说明实现,允许这样做。考虑到这些怪事,简明扼要的措辞往往是错误的。
    • @MSalters:这实际上是不合法的。功能为外联;它们在所有 TU 中具有相同的地址。否则,函数指针模板参数将无法工作(与字符串不能作为模板参数的原因相同)。函数指针必须指向在所有 TU 中具有相同地址的外部链接函数。
    • @DeadMG:你会注意到什么?根据我的建议,仍然有一个唯一的地址。它恰好位于 within 另一个函数中,但缺少sizeof(function),您无法在可移植代码中确定这一点。 IOW,sehe 的声明本质上是“内联和外部可见是相互排斥的”,我对此表示异议。
    【解决方案2】:

    C++ 标准是否保证两个指向函数的指针总是 比较相等?

    是的,指向同一个函数的两个指针比较相等。

    如果有一个带有内联的公共标头,这仍然成立吗 函数,以及主程序和动态加载的插件 (共享对象/DLL)创建指向函数的指针?

    是的,根据 7.1.2.p4

    具有外部链接的内联函数应具有相同的地址 在所有翻译单元中。

    【讨论】:

    • DLL 在技术上是未定义的行为。你不能这么简单。在实践中,没有合理的方法让编译器知道它需要从哪个 DLL 导入 std::map<std::string, std::complex<float>>::size(),因此您最终可能会得到多个副本和多个地址。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 2012-01-25
    • 1970-01-01
    • 2015-11-25
    相关资源
    最近更新 更多