0

我正在使用一个实现命令外壳的 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 函数,然后可以调用一些东西,它会给它一个指向我想要的实例的指针/引用,然后一旦我有了它,我就可以将调用转发到该实例的成员函数。它看起来有点乱,希望有更好的方法。

4

2 回答 2

1

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

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

于 2013-05-17T21:10:44.013 回答
0

由于您使用的是 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}
}
于 2013-05-17T21:10:31.977 回答