【问题标题】:using c++ class member function with C function pointer使用带有 C 函数指针的 C++ 类成员函数
【发布时间】:2013-05-17 20:44:36
【问题描述】:

我正在使用一个实现命令外壳的 C 库。通过实现具有以下调用签名的函数来注册自定义 shell 命令:

typedef void(* shellcmd_t)(BaseSequentialStream *chp, int argc, char *argv[])

然后在静态结构中注册该函数,该结构将字符串命令名称映射到该函数指针,如下所示:

static const ShellCommand commands[] = {
  {"myfunction", myfunction},
  {NULL, NULL}
}

myfunction 的样子:

void myfunction(BaseSequentialStream *chp, int argc, char *argv[])
{
   // do some stuff
}

我正在使用 C++,并希望将一些 shell 命令实现为类实例成员函数(不是静态成员函数)。有没有办法使用<functional> 中的任何内容,以便我可以从类实例成员函数中获取兼容的函数指针并将其注册到 ShellCommand 结构的数组中?我一直在阅读有关 std::bind 和 std::function 的内容,并且有点印象你可以给他们一个指向 C 风格函数的指针,但是你不能从他们,所以它似乎不起作用,但也许我只是错过了一些东西。

如果有人有解决这个问题的好方法,我很想听听。似乎我可能必须将它实现为一个平面 C 函数,然后可以调用一些东西,它会给它一个指向我想要的实例的指针/引用,然后一旦我有了它,我就可以将调用转发到该实例的成员函数。看起来有点乱,希望有更好的方法。

【问题讨论】:

  • 通过“C 风格函数”,您需要extern "C" 语言链接,还是仅仅需要一个普通函数(不是函数对象或成员函数)?
  • 我不完全确定,但确实知道类静态函数可以在没有外部“C”包装器的情况下工作——这是否意味着语言链接无关紧要,只是函数是普通的功能?
  • 联动在很多平台上无所谓,但不保证无所谓。你是对的,它必须是一个普通函数,因为成员函数有一个额外的隐藏参数来传递this。在某些平台 (Windows) 上,this 的传递方式甚至与其他参数不同。

标签: c++ c callback function-pointers


【解决方案1】:

不,这不可能是您想要的直接方式。在 C 接口中,您无法以某种方式传递类的隐式实例,而 C 接口根本没有插槽。因此,您必须将指针显式传递给实例并调用类函数。这样做的好处是保护了其他类方法。

所有这些都与extern "C" 链接的名称修饰方面无关,但最终与 ABI 相关。一旦您从变量(此处为数组元素)中的编译单元导出指向函数的指针,“原始”符号是否被损坏都无关紧要。类型系统保证始终使用正确的调用约定调用函数。

【讨论】:

  • extern "C" 很重要,但可能与目标系统无关。见评论讨论herehere。它与 ABI 有关,而不是修饰。
【解决方案2】:

由于您使用的是 C 库,因此您应该将 extern "C" 函数传递给 C 库。这是为了确保将与 C ABI 兼容的函数传递给 C 库(这在 C ABI 和 C++ ABI 不同的系统上很重要)。由于 API 看起来很规则,您可以在 C++ 代码中使用宏来简化此操作:

#define DEFINE_SHELL_COMMAND(cmd) \
    extern "C" void cmd##_c_wrap (BaseSequentialStream *chp, int argc, char *argv[]) { \
        cmd().execute(chp, argc, argv); \
    } \
    ShellCommand cmd##Entry = { #cmd, cmd##_c_wrap }

class ShellCommandClass {
protected:
    virtual ~ShellCommandClass () {}
public:
    virtual void execute (BaseSequentialStream *chp, int argc, char *argv[]) = 0;
};

class myfunctionClass : public ShellCommandClass {
    //...
public:
    void execute (BaseSequentialStream *chp, int argc, char *argv[]) { /* ... */ }
};

ShellCommandClass & myfunction () {
    static myfunctionClass cmd;
    return cmd;
}

DEFINE_SHELL_COMMAND(myfunction);

static const ShellCommand commands[] = {
    myfunctionEntry,
    {NULL, NULL}
}

【讨论】:

    猜你喜欢
    • 2011-10-27
    • 2014-10-03
    • 2018-09-12
    • 2012-02-29
    • 2010-11-02
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多