【问题标题】:How to store various types of function pointers together?如何将各种类型的函数指针存储在一起?
【发布时间】:2011-07-10 09:21:42
【问题描述】:

可以使用通用void* 存储普通指针。例如

void* arr[10];
arr[0] = pChar;
arr[1] = pINt;
arr[2] = pA;

以前,我遇到过一个讨论,void* 可能无法在所有平台(比如 64 位及更多)中存储函数指针而不会丢失数据。不过我不确定这个事实。

如果这是真的,那么存储函数指针集合的最便携方式是什么? [注:This question 对此没有满意的回答。]

编辑:我将用索引存储这个函数指针。每当访问此集合时,每个索引都会有一个类型转换。截至目前,我只想制作一个数组或vector。]

【问题讨论】:

  • 你将如何调用函数?您必须以某种方式恢复函数指针的原始类型。为了回答您的问题,了解这一点很重要。
  • 函数指针有 anything 的共同点吗?一旦它们进入收藏夹,您将如何处理它们?
  • @ybungalobill,我已经编辑了我的问题。截至目前,我想要一个普通的数组。不想诉诸template 解决方案。
  • @iammilind:如果我理解正确,那么您知道索引 0 是 X 类型,索引 1 是 Y 类型,等等......那你为什么不使用函数指针的结构那些已知类型(X f0; Y f1; ...)?如果你不能这样做,那意味着你确实有一些共同点(你对这个集合的每个项目所做的统一操作)。所以,请帮助我们了解您的设计选择。请注意,您使用 void* 的示例在实际代码中也没有意义。
  • @Shin:标准冲突。 C++ 和 C 都表示不应将函数指针强制转换为 void*(未定义行为)。 POSIX 说它们必须能够被强制转换为 void* (大概 Windows 也这么说;它使用 DLL)。 C 和 C++ 拒绝的原因:有很多奇怪的架构机器,其中函数指针与数据指针非常非常不同。 POSIX 说“是”的原因是:POSIX 不关心哈佛架构机器。

标签: c++ c function-pointers


【解决方案1】:

您可以将一个函数指针转换为任何函数类型的另一个函数指针并返回而不会丢失。

因此,只要在通过函数指针进行调用时首先将其类型转换回正确的类型,就可以将所有函数指针存储在以下内容中:

typedef void (*fcn_ptr)(void);  // 'generic' function pointer

fcn_ptr arr[10];

【讨论】:

  • +1 仅表示正确答案。您可能应该引用标准,因为 SO 的其余部分似乎认为 OP 的完全合理的要求被误导、非法或无法正确使用。
【解决方案2】:

可以将指向函数的指针转换为指向具有reinterpret_cast 的不同类型函数的指针。如果您将其转换回原始类型,则可以保证恢复原始值,以便您可以使用它来调用函数。 (ISO/IEC 14882:2003 5.2.10 [expr.reinterpret.cast] / 6)

您现在只需为数组选择任意函数指针类型。 void(*)() 是常见的选择。

例如

int main()
{
    int a( int, double );
    void b( const char * );

    void (*array[])() = { reinterpret_cast<void(*)()>(a)
                        , reinterpret_cast<void(*)()>(b) };

    int test = reinterpret_cast< int(*)( int, double) >( array[0] )( 5, 0.5 );
    reinterpret_cast< void(*)( const char* ) >( array[1] )( "Hello, world!" );
}

当然,如果您通过指向不同类型函数的指针调用函数,您将失去很多类型安全性,并且您将有未定义的行为

【讨论】:

  • 这对联合解决方案没有任何改进。更糟糕的是,因为联合可以在一个类中,该类控制并记住它所持有的函数指针类型。此外,reinterpret_cast无法如果您在过渡期间将原始数据存储在某个更窄的变量中,则可以恢复原始数据。
  • @spraff:我明确地谈论了从一个指向函数类型的指针转​​换为另一个指向函数类型的指针,然后再转换回原始类型的特殊情况。您保证可以取回原始值。查看我的参考资料。
  • @spraff:就我个人而言,我没有看到使用函数指针联合的优势。读取错误的联合成员与重新解释指向错误类型的函数指针一样危险存储在其中,这是一种维护开销,没有额外的好处。
  • 就个人而言,我更喜欢查尔斯的方法。一是诚实。 reinterpret_cast 暗示正在发生不正当的事情。二、扩展性强。三,我就是不喜欢工会。他们可以追溯到 Fortran EQUIVALENCE 时代。
【解决方案3】:

使用函数指针类型的联合,这适用于 C 和 C++,并确保指针有足够的存储空间(可能大小相同,仍然...)

【讨论】:

    【解决方案4】:

    函数指针的类型由几项组成。

    • 代码的内存地址
    • 参数签名
    • 链接/名称修改
    • 调用约定
    • 对于成员函数,some other stuff too

    如果这些功能在您的函数指针中不一致,那么您就不能明智地将它们存储在同一个容器中。

    但是,您可以将 bind different aspects 转换为 std::function,这是一个可调用对象,只需要参数签名和返回类型是统一的。

    现在可能是从虚函数的角度重新思考问题的好时机。这种函数指针的混搭是否有一个可以表达的连贯接口?如果没有,那么你无论如何都注定要失败:-)

    RE:Hasturkun,您可以将异构函数指针存储在联合中,是的,它们只是 POD,但您还需要存储有关它是什么类型的指针的信息,以便您可以选择要调用的正确成员。这有两个问题:

    • 存在每项开销,
    • 您必须手动检查您是否始终始终使用正确的,这是非局部效应的负担——它是一种传播毒药。

    每种类型都有一个容器要好得多,它会澄清代码并使其更安全。或者,使用std::function 等代理使它们都具有相同的类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-08
      • 2013-03-27
      • 1970-01-01
      相关资源
      最近更新 更多