当前位置:  开发笔记 > 编程语言 > 正文

为什么我们需要在C++中使用extern"C"{#include <foo.h>}?

如何解决《为什么我们需要在C++中使用extern"C"{#include<foo.h>}?》经验,为你挑选了10个好方法。

为什么我们需要使用:

extern "C" {
#include 
}

特别:

我们什么时候应该使用它?

在编译器/链接器级别发生了什么,需要我们使用它?

如何在编译/链接方面解决了需要我们使用它的问题?

duane.. 121

C和C++在表面上相似,但每个编译成一组非常不同的代码.当您使用C++编译器包含头文件时,编译器需要C++代码.但是,如果它是一个C头,则编译器需要将头文件中包含的数据编译为某种格式--C++'ABI'或'应用程序二进制接口',因此链接器会扼杀.这比将C++数据传递给期望C数据的函数更可取.

(为了深入了解真正的细节,C++的ABI通常会"破坏"它们的函数/方法的名称,所以在printf()不将原型标记为C函数的情况下进行调用_Zprintf,C++实际上会生成代码调用,最后加上额外的废话. )

所以:extern "C" {...}当包括ac头时使用- 就这么简单.否则,您将在编译的代码中出现不匹配,并且链接器将会阻塞.但是,对于大多数标头,您甚至不需要它,extern因为大多数系统C标头已经考虑到它们可能包含在C++代码中并且已经包含extern它们的代码.



1> duane..:

C和C++在表面上相似,但每个编译成一组非常不同的代码.当您使用C++编译器包含头文件时,编译器需要C++代码.但是,如果它是一个C头,则编译器需要将头文件中包含的数据编译为某种格式--C++'ABI'或'应用程序二进制接口',因此链接器会扼杀.这比将C++数据传递给期望C数据的函数更可取.

(为了深入了解真正的细节,C++的ABI通常会"破坏"它们的函数/方法的名称,所以在printf()不将原型标记为C函数的情况下进行调用_Zprintf,C++实际上会生成代码调用,最后加上额外的废话. )

所以:extern "C" {...}当包括ac头时使用- 就这么简单.否则,您将在编译的代码中出现不匹配,并且链接器将会阻塞.但是,对于大多数标头,您甚至不需要它,extern因为大多数系统C标头已经考虑到它们可能包含在C++代码中并且已经包含extern它们的代码.


@BulatM.它们包含这样的内容:`#ifdef __cplusplus extern"C"{#endif`因此,当从C++文件中包含它们时,它们仍被视为C头.

2> Todd Gamblin..:

extern"C"确定应如何命名生成的目标文件中的符号.如果声明的函数没有extern"C",则目标文件中的符号名称将使用C++名称修改.这是一个例子.

鉴于test.C如此:

void foo() { }

在目标文件中编译和列出符号给出:

$ g++ -c test.C
$ nm test.o
0000000000000000 T _Z3foov
                 U __gxx_personality_v0

foo函数实际上称为"_Z3foov".该字符串包含返回类型和参数的类型信息等.如果您改为编写test.C,如下所示:

extern "C" {
    void foo() { }
}

然后编译并查看符号:

$ g++ -c test.C
$ nm test.o
                 U __gxx_personality_v0
0000000000000000 T foo

你得到C联动.目标文件中"foo"函数的名称只是"foo",它没有来自名称修改的所有花哨类型信息.

您通常在extern"C"{}中包含一个标头,如果与它一起使用的代码是使用C编译器编译的,但您尝试从C++调用它.执行此操作时,您告诉编译器标头中的所有声明都将使用C链接.当你链接你的代码时,你的.o文件将包含对"foo"的引用,而不是"_Z3fooblah",它有希望匹配你链接的库中的任何内容.

大多数现代图书馆都会在这些标题周围放置警卫,以便用正确的链接声明符号.例如,你会发现很多标准的标题:

#ifdef __cplusplus
extern "C" {
#endif

... declarations ...

#ifdef __cplusplus
}
#endif

这可以确保当C++代码包含标题时,目标文件中的符号与C库中的符号相匹配.你应该只需要在你的C标题周围放置extern"C"{}如果它已经老了并且没有这些警卫.


一些简短的例子真是好事!

3> Trent..:

在C++中,您可以拥有共享名称的不同实体.例如,这里是一个名为foo的函数列表:

A::foo()

B::foo()

C::foo(int)

C::foo(std::string)

为了区分它们,C++编译器将在名为name-mangling或decorating的过程中为每个创建唯一的名称.C编译器不这样做.此外,每个C++编译器可能会以不同的方式执行此操作.

extern"C"告诉C++编译器不要对大括号内的代码执行任何名称修改.这允许您从C++中调用C函数.



4> 1800 INFORMA..:

它与不同编译器执行名称修改的方式有关.C++编译器将以与C编译器完全不同的方式破坏从头文件导出的符号的名称,因此当您尝试链接时,您将收到链接器错误,指出缺少符号.

为了解决这个问题,我们告诉C++编译器以"C"模式运行,因此它以与C编译器相同的方式执行名称修改.完成后,链接器错误是固定的.



5> tialaramex..:

C和C++对符号名称有不同的规则.符号是链接器如何知道编译器生成的一个目标文件中对"openBankAccount"函数的调用是对在另一个源文件中由同一个(或兼容的)生成的另一个目标文件中称为"openBankAccount"的函数的引用.编译器.这允许您使用多个源文件创建程序,这在处理大型项目时是一种解脱.

在C中,规则非常简单,无论如何符号都在一个名称空间中.因此整数"socks"存储为"socks",函数count_socks存储为"count_socks".

使用这个简单的符号命名规则,连接器是为C和其他语言(如C)构建的.所以链接器中的符号只是简单的字符串.

但是在C++中,该语言允许您拥有名称空间,多态性以及与这样一个简单规则冲突的各种其他内容.所有六个称为"add"的多态函数都需要有不同的符号,否则其他目标文件将使用错误的符号.这是通过"修改"(这是技术术语)符号的名称来完成的.

当将C++代码链接到C库或代码时,您需要使用C编写的任何外部"C",例如C库的头文件,以告诉您的C++编译器这些符号名称不会被破坏,而其余的您的C++代码当然必须被破坏,否则将无效.



6> 小智..:

我们什么时候应该使用它?

将C库链接到C++目标文件时

在编译器/链接器级别发生了什么,需要我们使用它?

C和C++使用不同的符号命名方案.这告诉链接器在给定库中链接时使用C的方案.

如何在编译/链接方面解决了需要我们使用它的问题?

使用C命名方案可以引用C风格的符号.否则链接器将尝试C++样式的符号,这些符号不起作用.



7> mbyrne215..:

C++编译器创建符号名称的方式与C编译器不同.因此,如果您尝试调用驻留在C文件中的函数(编译为C代码),则需要告诉C++编译器它尝试解析的符号名称与默认值不同; 否则链接步骤将失败.



8> HitScan..:

在包含定义函数的头的任何时候都应该使用extern"C",这些函数驻留在由C编译器编译的文件中,在C++文件中使用.(许多标准C库可能在其标题中包含此检查,以使开发人员更容易)

例如,如果你有一个包含3个文件的项目,util.c,util.h和main.cpp,并且.c和.cpp文件都是用C++编译器(g ++,cc等)编译的,那么它就不是'真的需要,甚至可能导致链接器错误.如果构建过程对util.c使用常规C编译器,则在包含util.h时需要使用extern"C".

发生的事情是C++在其名称中编码函数的参数.这就是函数重载的工作原理.所有倾向于发生在C函数中的都是在名称的开头添加下划线("_").如果不使用extern"C",当函数的实际名称是_DoSomething()或DoSomething()时,链接器将查找名为DoSomething @@ int @ float()的函数.

使用extern"C"通过告诉C++编译器应该查找遵循C命名约定而不是C++约定的函数来解决上述问题.



9> Paul Lalonde..:

extern "C" {}构造指示编译器不对在大括号内声明的名称执行修改.通常,C++编译器"增强"函数名称,以便它们编码有关参数和返回值的类型信息; 这被称为受损名称.该extern "C"构造防止了整理.

它通常在C++代码需要调用C语言库时使用.当将C++函数(例如,从DLL)暴露给C客户端时,也可以使用它.



10> Eric Z Beard..:

这用于解决名称重整问题.extern C意味着函数采用"扁平"C风格的API.

推荐阅读
雯颜哥_135
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有