为什么C++回调C函数需要"extern C"?

Art*_*yom 17 c c++ callback extern-c

我在Boost代码中找到了这样的例子.

namespace boost {
   namespace {
     extern "C" void *thread_proxy(void *f)
     {
       ....
     }

   } // anonymous
   void thread::thread_start(...)
   {
       ...
       pthread_create(something,0,&thread_proxy,something_else);
       ...
   }
} // boost
Run Code Online (Sandbox Code Playgroud)

你为什么真的需要这个extern "C"

很明显,该thread_proxy函数是私有内部的,我不认为它会被破坏为"thread_proxy",因为我实际上根本不需要它.

实际上,在我编写的所有代码中,我在许多平台上运行,我从未使用过,extern "C"而且这个代码与普通函数一样正常.

为什么要extern "C"添加?


我的问题是extern "C"函数污染了全局命名空间,并且它们实际上并没有像作者所期望的那样被隐藏.

这不是重复的! 我不是在谈论破坏和外部联系.在此代码中很明显,外部链接是不需要的!

答: C和C++函数的调用约定不一定相同,因此您需要使用C调用约定创建一个.参见C++标准的7.5(p4).

GMa*_*ckG 17

很明显,该thread_proxy函数是私有内部的,我不认为它会被破坏为"thread_proxy",因为我实际上根本不需要它.

无论如何,它仍然会受到损害.(如果没有extern "C")这就是编译器的工作原理.我同意可以想象一个编译器可以说"这不一定需要被修复",但标准上没有说明任何内容.也就是说,在这里没有发挥作用,因为我们没有尝试链接到该功能.

实际上,在我编写的所有代码中,我在许多平台上运行,我从未使用过,extern "C"而且这个代码与普通函数一样正常.

在不同平台上写作与此无关extern "C".我希望所有标准C++代码都能在所有具有标准C++兼容编译器的平台上运行.

extern "C"与C接口有关,pthread是一个库.它不仅不会破坏名称,还确保它可以使用C调用约定进行调用.这是需要保证的调用约定,因为我们不能假设我们在某个编译器,平台或体系结构上运行,尝试这样做的最好方法是使用给我们的功能:extern "C".

我的问题是extern "C"函数污染了全局命名空间,并且它们实际上并没有像作者所期望的那样被隐藏.

上面的代码没有任何污染.它位于未命名的命名空间中,无法在翻译单元外访问.

  • @Artyom - x86,Borland C++编译器.它默认使用fastcall用于C++函数. (3认同)
  • @GMan:在Linux(Ubuntu)上使用g ++ 4.4,在翻译单元外面也可以看到符号.我认为将符号标记为内部链接的正确方法是在extern"C"中将其声明为静态,因为extern"C"函数会忽略它们所在的任何名称空间(包括未命名的名称空间). (2认同)

gre*_*ade 6

extern "C"链接并不一定意味着只有名称重整被抑制.事实上,有可能是一个编译器,它把extern "C"一个不同的调用约定.

标准将此完全打开作为实现定义的语义.

  • 这与任何事情有什么关系?您是否希望编写仅适用的代码,因为您非常熟悉已编写的每个C++实现的调用约定,并应用该知识?或者您是否希望编写适用于C++标准的任何实现的代码,因为您执行标准所说的必须为您想要的结果做的事情?将来,您是否要写入标准,因为有人指出了一个需要extern"C"的实现,或者因为实际上您并不熟悉每个编译器? (4认同)

Dan*_*ker 5

这个问题是有效的 - 虽然函数被传递给C库,但C库根本没有链接到C++代码.它只给出了函数的地址,因此它对函数的名称根本没有兴趣.

关键在于,extern "C"最接近于跨平台的方式告诉编译器使该函数在该平台上使用标准C调用约定(即确切地如何在堆栈上传递参数和返回值).

不幸的是,它还具有在全局级别创建外部链接器符号的副作用.但是,可以通过使用类似的名称来减轻这种情况boost_detail_thread_proxy.