17

我在 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

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

很明显,该thread_proxy函数是私有的内部函数,我不希望它被修改为“thread_proxy”,因为我实际上根本不需要它。

事实上,在我编写并在许多平台上运行的所有代码中,我从未使用过extern "C",而且这与正常功能一样工作。

为什么要extern "C"添加?


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

这不是重复的! 我不是在谈论修饰和外部链接。在这段代码中很明显不需要外部链接!

答: C 和 C++ 函数的调用约定不一定相同,所以需要创建一个具有 C 调用约定的。请参阅 C++ 标准的 7.5 (p4)。

4

6 回答 6

17

很明显,该thread_proxy函数是私有的内部函数,我不希望它被修改为“thread_proxy”,因为我实际上根本不需要它。

无论如何,它仍然会被破坏。(如果不是extern "C")这就是编译器的工作方式。我同意编译器可以说“这不一定需要修改”是可以想象的,但标准没有说明它。也就是说,修改在这里并没有发挥作用,因为我们没有尝试链接到该函数。

事实上,在我编写并在许多平台上运行的所有代码中,我从未使用过extern "C",而且这与正常功能一样工作。

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

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

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

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

于 2010-04-07T16:37:53.800 回答
6

extern "C"链接并不一定意味着只抑制名称修改。事实上,可能有一个编译器将其视为extern "C"不同的调用约定。

该标准将其完全开放为实现定义的语义。

于 2010-04-07T16:37:47.667 回答
5

这个问题是有效的——尽管函数被传递给 C 库,但该 C 库根本没有链接到 C++ 代码。它只给出了函数的地址,所以它对函数的名称完全没有兴趣。

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

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

于 2010-04-07T16:42:55.907 回答
1

它用于使函数使用编译器通过 C 调用约定理解的任何内容,同时避免编译器特定的关键字,例如__cdecl.


这里的所有都是它的。这与名称修改、命名空间或任何其他奇怪的答案完全无关(正如您在询问时已经知道的那样)。

于 2010-04-07T17:07:56.253 回答
0

可能是因为您正在连接一个普通的 C 库——pthreads。

于 2010-04-07T16:35:06.833 回答
0

由于不能保证 C 和 C++ 具有相同的调用约定,因此您需要声明回调函数extern "C",以便将其传递给pthread_createC 函数。

上面的thread_proxy函数具有外部链接(即在其翻译单元之外可见),因为名称空间对extern "C"函数没有影响——即使是匿名名称空间。相反,要为thread_proxy函数提供内部链接,您需要将其声明为静态:

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

[编辑] 请注意,boost 已包含此更改。见https://svn.boost.org/trac/boost/ticket/5170

于 2011-02-08T20:14:15.180 回答