extern C不能在课堂上使用?

只想在Windows环境下确认VSTS 2008 + C ++项目,我们只能将extern C应用到function级别,而不能应用于类级别(这样所有成员函数都从类中使用C语言名称修改)? 我尝试了几种方法,但始终编译错误。

乔治,提前谢谢

您可以通过一个非常复杂(但完全合法)的黑客将extern "C"应用于成员函数:

 extern "C" typedef int bar_t(int x); struct foo { bar_t bar; // yes, this declares a nonstatic member function! }; int foo::bar(int x) { return x; } // definition 

这可以根据ISO C ++ 03 9.3 [class.mfct] / 9:

可以使用typedef为函数类型声明(但未定义)成员函数。 结果成员函数与明确提供函数声明符时的类型完全相同,见8.3.5。

但是,由于ISO C ++ 03 7.5 [dcl.link] / 4,这并不能真正为你买任何东西。

对于类成员的名称和类成员函数的成员函数类型,将忽略AC语言链接。

extern“c”使用c风格的链接; 也就是说,原始函数名称是从库中公开的。 因为它只是一个原始函数名,所以只有C ++的function才能使用它,包括名称空间,类,结构或联合中的方法或外部数据成员。

澄清 :结构和联合在C中,但没有成员函数,因此它们在C ++中的成员函数不能以c风格导出(并且不需要导出结构和联合定义,因为它已经在标题中)

恐怕不是。 但是如果你想将C ++的对象传递给C函数,你可以参考这个链接: http : //www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.8

看看你在前一个答案上发表的评论(“问题是我们是否可以在类级别应用extern C ,以便类中的所有函数自动具有C样式名称修改?”,答案是’ extern "C"并不是那么好用。”

从语法上讲, extern "C"可以应用于curl分隔块的单个语句:

 extern "C" int my_foo(int i) { ... } extern "C" { int my_bar(int i) { ... } int my_baz(int i) { ... } } 

在整个C头上使用带有相应#ifdef __cplusplus保护的extern "C"是很常见的。

从语义上讲,应用extern "C"的实际效果仅适用于“普通”(即非类)函数和指向函数的指针。 当然,您无法将其应用于C ++模板。 你也不能将它应用于类方法(因为类方法需要知道调用它的对象,并且C风格的链接没有任何方法将该信息传递给函数)。

可以在命名空间中存在的函数上应用extern "C" ,但是当通过C使用时,命名空间信息将消失。


更新

如果你已经有了一个类(我们将使用POD类来简化),并且你想让它可以从C中使用,你需要将extern "C"应用于可在C语言中调用的函数。不幸的是,这甚至变得难看在简单的情况下:

 // in the header file #ifdef __cplusplus namespace X { #endif struct A { int x; #ifdef __cplusplus A() : x(5) { } int foo() { return x += 5; } #endif }; #ifdef __cplusplus extern "C" { #endif int A_foo(struct A a); struct A A_create(); #ifdef __cplusplus } } #endif // in the .cc file #include "try.h" namespace X { extern "C" { int A_foo(A* a) { return a.foo(); } A A_create() { return A(); } } } // in the .c file #include  #include "try.h" int main() { struct A a = A_create(); printf("%d", A_foo(a)); } 

使用gcc你可以编译如下:

  • C ++文件: g++ try.cc -c -o try.o
  • C文件: gcc try.c try.o

有几点重要:

  • 如果您的C ++文件在后台调用STL,或调用newdelete (或new[]delete[] ),则需要将最终程序链接到C ++运行时库(gcc中的命令行开关是-lstdc++
  • 在编译C和C ++代码时,您可能想要传递相同的优化标志(优化会影响对象的大小,如果大小不匹配,则会遇到很多麻烦)。 multithreading也是如此。
  • 您可以在C ++代码中使用所有您想要的exception,但是一旦它们跨越C代码,所有的赌注都会关闭 。
  • 如果你想要更复杂的东西,你可能想看看PIMPL模式。
  • 当结构超出C代码的范围时, 不会调用C ++析构函数(某些编译器可能会保证这样做,但它不是标准的)。 如果你需要对这些对象进行任何清理,你需要调用一个调用析构函数的extern“C”函数。

要显式调用析构函数:

 extern "C" void A_destroy(struct A a) { a.~A(); } 

嗯… extern "C"强制C式联动。 它不能用于AFAIK类。