什么样的 C++ 函数可以放在 C 函数指针中?

What kinds of C++ functions can be placed in a C function pointer?

我有一个 C 库,它使用函数指针结构进行回调。将从 C 代码调用回调。

extern "C" {
typedef struct callbacks_t {
    void (*foo) (const char*);
    int  (*bar) (int);  
} callbacks_t;
}// extern C

我可以安全地将哪些类型的 C++ 函数放在那些函数指针中,以便从 C 库中调用?静态成员函数?完全指定的模板函数?非捕获 Lambda?

g++ 似乎可以让我使用以上所有功能,但我质疑将不同的调用约定和语言绑定用于 C 和 C++ 函数时的安全性。

一般来说,除非你使用cast,否则你应该相信g++。

虽然您提到的 none 函数类型确实可以导出以在 C 中使用,但这不是您要问的。你问的是什么函数可以作为函数指针传递。

回答你能通过的,我觉得了解你不能通过的更有建设性。您不能传递任何需要参数列表中未明确说明的额外参数的内容。

所以,没有非静态方法。他们需要一个隐含的 "this"。 C不知道要通过它。再一次,编译器不会让你。

没有捕获 lambda。他们需要一个隐式参数与实际的 lambda 主体。

您可以传递的是不需要隐式上下文的函数指针。事实上,您继续列出了它们:

  • 函数指针。不管是标准函数还是模板,只要模板完全解析就可以了。这不是问题。您编写的任何导致函数指针的语法都将自动完全解析模板。
  • 非捕获 lambda。这是 C++11 在引入 lambda 时引入的一种特殊变通方法。由于可以这样做,编译器会进行所需的显式转换。
  • 静态方法。因为它们是静态的,所以它们不会被隐式传递 this,所以它们没问题。

最后一个值得继续扩展。许多 C 回调机制都有一个函数指针和一个 void* opaq。以下是将它们与 C++ class:

一起使用的标准且相当安全
class Something {
  void callback() {
    // Body goes here
  }

  static void exported_callback(void *opaq) {
    static_cast<Something*>(opaq)->callback();
  }
}

然后做:

Something something;

register_callback(Something::exported_callback, &something);

编辑添加: 这样做的唯一原因是因为当没有传递隐式参数时,C++ 调用约定和 C 调用约定是相同的。名称修饰有所不同,但当您传递函数指针时它并不相关,因为名称修饰的唯一目的是让链接器找到正确的函数地址。

如果您尝试使用预期回调的技巧,例如 stdcall 或 pascal 调用约定,这个方案就会完全失败。

然而,这并不是静态方法、lambda 和模板函数所独有的。在这种情况下,即使是标准函数也会失败。

遗憾的是,当您定义一个指向 stdcall 类型的函数指针时,gcc 会忽略您:

#define stdcall __attribute__((stdcall))
typedef stdcall void (*callback_type)(void *);

结果:

test.cpp:2:45: warning: ‘stdcall’ attribute ignored [-Wattributes]
 typedef stdcall void (*callback_type)(void *);

I have a C library that uses a struct of function pointers for callbacks. The callbacks will be called from C code.

C 库只理解 C。所以你只能传回 C 明确支持和理解的东西。

由于在 C++ 中没有定义任何函数类型的调用约定,因此您不能显式传回 C++ 函数。您只能传回 C 函数(那些用 extern "C" 显式声明的函数)并保证它们兼容。

像所有未定义的行为一样,这似乎可行(例如传回正常的 C++ 函数或静态成员)。但就像所有未定义的行为一样,它是允许工作的。你只是不能保证它实际上是正确的或可移植的。

extern "C" {
    typedef struct callbacks_t {
        void (*foo) (const char*);
        int  (*bar) (int);  
    } callbacks_t;

    // Any functions you define in here.
    // You can set as value to foo and bar.

}// extern C

What kinds of C++ functions can I safely place in those function pointers to be called from the C library?

Static member functions?

没有。但这恰好适用于很多平台。这是一个常见的错误,会在某些平台上咬人。

Fully specified template functions?

没有。

Non-capturing Lambdas?

没有

g++ seemingly lets me use all of the above,

是的。但假设您要传递给使用 C++ 编译器构建的对象(这将是合法的)。因为 C++ 代码将使用正确的调用约定。问题是当您将这些东西传递给 C 库时(想到 pthreads)。