专栏首页用户6269484的专栏C和C++混合编译,extern和extern "C"
原创

C和C++混合编译,extern和extern "C"

extern的问题在于你不知道这个关键字出现的时候到底是声明还是定义。  谨记:声明可以多次,但是定义只能有一次。

函数的声明extern关键字是可有可无的,因为函数本身不加修饰的话就是extern的。

下面分变量和函数来说明:  (1) 变量  extern int a; //声明一个全局变量 int a; //定义一个全局变量

extern int a = 0;//定义全局变量并给初值 int a = 0; //定义全局变量并给初值 上面的四个只有第一个extern int a才是声明,其他的全是定义。  当你要引用一个全局变量时,你就要声明extern int a;这个时候extern不能省,否则就成定义了。

(2) 函数  函数也有声明和定义,但由于函数的声明和定义是有区别的,函数的定义是有函数体的,所以函数的声明和定义都可以将extern省略掉,反正其他文件也是知道这个函数是在其他地方定义的。

extern “C”:   作为C语言的扩展,C++保留了一部分过程式语言的特点,因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的设计语言,为了支持函数的重载,C++对全局函数的处理方式有着明显的不同。    首先看一下C++对类似C的函数是怎样编译的:    作为面向对象的语言,C++为了支持函数重载,函数在被C++编译后在符号库中的名字与C语言的不同。假如某个函数的原型为void foo(int x, int y);该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生_foo_int_int之类的名字。_foo_int_int这样的名字是包含了函数名以及形参,C++就是靠这种机制来实现函数重载的。    被extern “C”修饰的函数或者变量是按照C语言方式编译和链接的,所以可以用一句话来概括extern “C”的真实目的:实现C++与C的混合编程。

extern “C”的惯用法:  (1) 在C++中引用C语言中的函数和变量,在包含C语言头文件时(假设为cExample.h),需进行以下处理:  extern "C" { #include "cExample.h"; }

  而在C语言的头文件中,对其外部函数只能指定为extern,C语言中不支持extern “C”,会报编译错误。

  笔者编写的C++引用C函数的例子工程,包含的三个文件如下  /* c语言头文件:cExample.h */ #ifndef C_EXAMPLE_H #define C_EXAMPLE_H extern int add(int x, int y); #endif

/* c语言的实现文件:cExample.c */ #include "cExample.h" int add(int x, int y) { return x + y; }

/* c++实现文件,调用add:cppFile.cpp */ extern "C" { #include "cExample.h"; } int main() add(2, 3);  return 0;  } `    如果C++调用一个C语言编写的.DLL时,在包含.DLL的头文件或声明接口函数时,应该也要加上extern “C”。

(2) C中引用C++语言中的函数或者变量时,C++的头文件需要加上extern “C”,但是C语言中不能直接引用声明了extern “C”的该头文件,应该仅在C中将C++中定义的extern “C”函数声明为extern类型。

  笔者编写的C引用C++函数的例子工程,源文件代码如下:  /* c++头文件cppExample.h */ #ifndef CPP_EXAMPLE_H #define CPP_EXAMPLE_H extern "C" int add(int x, int y); #endif

/* c实现文件cFile.c */ extern int add(int x, int y); int main() { add(2, 3); return 0; }

总结:

extern "C"是告诉C++编译器以C Linkage方式编译,也就是抑制C++的name mangling机制。例如:

void Test(void);

C++编译器可能实际把它改名为vTest_v,C++的重载/namespace等机制就是这样来的。而

extern "C" void Test(void)

则和C编译器一样为_Test。

主要用于在C++代码中调用的C函数的声明,或C++中编译的函数要在C中调用。

也就是说extern有两个作用,第一个,当它与"C"一起连用时,如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目全非,可能是fun@aBc_int_int#%$也可能是别的,这要看编译器的"脾气"了(不同的编译器采用的方法不一样),为什么这么做呢,因为C++支持函数的重载啊,在这里不去过多的论述这个问题,如果你有兴趣可以去网上搜索,相信你可以得到满意的解释! 第二,当extern不与"C"在一起修饰变量或函数时,如在头文件中: extern int g_Int; 它的作用就是声明函数或全局变量的作用范围的关键字,其声明的函数和变量可以在本模块活其他模块中使用,记住它是一个声明不是定义!也就是说B模块(编译单元)要是引用模块(编译单元)A中定义的全局变量或函数时,它只要包含A模块的头文件即可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在连接时从模块A生成的目标代码中找到此函数。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • VSCode快捷键整理

    朵朵花儿
  • 利用 Settings Sync 同步vs code配置

    vs code上有各种各样不同的插件,如果要在不同的电脑上使用 vs code 配置是件比较麻烦的事情,使用 Settings Sync 将 vs code 配...

    朵朵花儿
  • vs code 打开顶部菜单栏和左侧菜单栏的方法

    按快捷键 F1 或者 shift+ctrl+p 切换出命令行,然后输入menu 有个view:toggle Menu bar 的功能,即可打开顶部菜单栏

    朵朵花儿
  • 以太坊智能合约开发第七篇:智能合约与网页交互

    Marser
  • 【专业知识】C/C++指针三

    今天我们主要介绍函数指针、函数的指针参数以及返回指针的函数 A) 函数指针   C++规定,一个函数的地址就是这个函数的名字。我们需要指出的就是一个指针需要指定...

    程序员互动联盟
  • NYOJ 108 士兵杀敌(一)

    题目链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=108

    Ch_Zaqdt
  • C++调用C链接库会出现的问题

    用户1258909
  • 【C语言笔记】函数指针作为函数的参数

    函数指针有两种常用的用法,一种是作为结构体成员,关于函数指针作为结构体成员的用法可移步至上一篇【C语言笔记】函数指针作为结构体成员进行查看。另一种是函数指针作为...

    正念君
  • 【C语言笔记】指针函数与函数指针?

    由于“*”的优先级低于“()”的优先级,因而pfun首先和后面的“()”结合,也就意味着,pfun是一个函数。即:int *(pfun(int, int));

    正念君
  • poj-----Ultra-QuickSort(离散化+树状数组)

    Ultra-QuickSort Time Limit: 7000MS Memory Limit: 65536K Total Submission...

    Gxjun

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动