文章目录

  • extern的含义
    • 修饰全局变量
    • 修饰全局常量
    • 修饰局部变量
    • 修饰字符串
      • C++代码
      • C代码

想必大家都知道,在C++中,想要生成一个可执行文件(exe)或者动态链接库(dll),需要经过编译和链接两个步骤,C++里面的变量也比C#分的更加细致,包括了声明和定义两个不同阶段。这些迥然不同于C#的细节,让很多从C#转向C++的程序员在学习伊始非常头疼。特别对于C++里的关键字extern,和它在不同上下文的不一样的含义,让很多程序员直呼好家伙。今天,就让我们聊聊它吧。

extern的含义

按照语法书的说法,extern一般有如下用途。

  • 修饰全局变量:在声明全局变量的时候使用extern修饰变量,表明该变量定义于其他翻译单元。
  • 修饰全局常量:表明该全局常量拥有外部链接(可以被其他翻译单元发现),否则全局常量默认是只有内部链接,即不可被其他翻译单元发现。
  • 修饰局部变量:表明该局部变量在其他翻译单元中被定义,需要在链接的时候去解析。
  • 修饰一个字符串:形如extern “C” 之类的用法大家肯定见过了,表明后接的代码块(或者后接的声明)使用C语言调用惯例。
  • 修饰一个模板:表明该模板已经在其他翻译单元实例化,不需要在这里实例化。

因为模板是一个很大的内容,extern修饰模板的使用今天暂且不谈,以后讲到模板的时候再说。我们重点谈谈前面几个含义。

修饰全局变量

如果想表明某个全局变量来自其他翻译单元,可用extern修饰,但如果此语句是一个变量定义,那么extern将被忽略。比如:

//file1
int i = 0; //默认拥有外部链接
extern int j; //j定义于其他翻译单元
extern int i = 10; //与 int i = 0 相同,这里extern被忽略,属于重复定义

请注意,对于全局变量,如果语句中没有extern也没有显示赋值,编译器(在VS2017中实测)会帮忙初始化变量为0,这种情况会视为变量定义,但是却不会与之后的变量定义发生冲突,所以这么写是可以的

//file1
int i; //编译器会帮忙初始化0
extern int i = 10; //第二次变量定义,但是这里却是允许的,变量变成了10

修饰全局常量

全局常量默认没有外部链接,所以extern的主要在于分享全局常量给其他翻译单元。

//file1
extern const int J = 10; //定义拥有外部链接的全局常量J//file2
extern const int J; //声明全局常量J来自于其他翻译单元

修饰局部变量

对于局部变量来说,extern可用于声明该局部变量来自其他翻译单元,但是不能使用extern定义一个拥有外部链接的局部单元

void Test()
{extern int i; //表明i来自于其他翻译单元extern int j = 20; //错误,因为局部变量的生命周期在退出函数的时候就结束了,所以不允许其建立外部链接
}

修饰字符串

C++向下兼容C,所以C++需要提供一种方式能和C代码互动。说起来应该是很简单的一件事,因为他们的语法都是一样的嘛,让我们试试(以下还是以vs2017为例)

C++代码

建立一个静态链接库,里面包含一个简单的方法Sum

//sum.cpp
int Sum(int i, int j)
{return i + j;
}

顺利编译成lib

C代码

建立一个C工程,创建一个main文件并使用刚刚建立的C++库。

//main.c
#include <stdio.h>int Sum(int i, int j); //函数声明int main(void)
{int result = Sum(1, 2); //使用函数return 0;
}

在工程属性中选择用C编译器,确保以C的惯例进行编译。

之后设置链接参数,确保链接器能拿到C++的lib。之后试着Build。

啊哦,链接器报错了,这是为什么呢?

究其原因,和C calling convention有关,我们都知道在C中没有函数重载,所以C的编译器一般不会把函数名重新编码(name mangling),而C++会把函数的参数,返回值甚至命名空间一起当做原材料,生成一个name mangling之后的字符串当做链接器里面的函数名字。所以这里C期望得到的Sum名字和C++那边提供的Sum名字对不上,也就自然找不到了。

要想解决这个问题,我们就需要以C的命名惯例编译C++库。修改代码如下:

//sum.cpp
extern "C"
{int Sum(int i, int j){return i + j;}
}

再次build,这次就一切正常了。所以大家可以知道extern 加字符串的作用了吧。类似的,如果是用C++代码调用C库,我们也可以使用extern "C++"来编译C库。但是请注意,在extern "C"里面需要严格遵守C规定,函数重载等是不被支持的。

关于Calling Convention和Name Mangling,也是一个比较大的话题,感兴趣的同学可以进一步在这里进行深入阅读。

从C#到C++的跨越需要非凡的努力,有非常多的东西要学,extern只是其中一个很小的知识点却也可见一斑,C++之于C#,难点在于更底层更强大,也就需要更多的耐心去研究,extern当时也困惑了我很久,希望通过这篇博客,能让和当时的我一样迷茫的朋友少走弯路。

希望大家喜欢,也希望大家点赞关注,跟着老胡一起学习C++。

C++中的extern相关推荐

  1. 何时在C ++中使用extern

    本文翻译自:When to use extern in C++ I'm reading "Think in C++" and it just introduced the exte ...

  2. c++中的 extern C

    c++中的 extern "C" 博客分类: c CC++C#GCCD语言  比如说你用C开发了一个DLL库,为了能够让C++语言也能够调用你的DLL输出(Export)的函数,你 ...

  3. C++项目中的extern C {}

    2010-07-10 19:45 by 吴秦, 92864 阅读, 22 评论, 收藏, 编辑 引言 在用C++的项目源码中,经常会不可避免的会看到下面的代码: ? 1 2 3 4 5 6 7 8 9 ...

  4. ida 中segment中的extern是什么

    紫色部分: extern不是真正的段它是IDA创建的一个伪段,用于表示其他模块中地址未知的符号: GOT通常包含指向这些符号的指针在调试过程中,它可能会被.bss所覆盖,或者被操作系统加载程序清除堆栈 ...

  5. 嵌入在C++程序中的extern C

    1.extern的作用 extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,可以告知编译器,用extern声明的函数和变量可以在本模块或其它模块中使用. 通常,在模块的头文件中 ...

  6. VLFeat库中加extern “C“

    使用VLFeat的时候官网有这么一句话,VLFeat是C的库,想要在C++中使用它就要加上extern "C" 如下: extern "C" { #includ ...

  7. C中的extern关键字

    main.c中 #include<stdio.h>#include "test.h" int a = 1; int b = 2; int main() {fun();/ ...

  8. Keil C 中全局变量 extern 的使用

    在KEIL C中,有多个源文件使用到全局变量时,可以在一个源文件中定义全局变量,在另外的源文件中用extern 声明该变量,说明该变量定义在别的文件中,将其作用域扩展到此文件. 例如:有以下两个源文件 ...

  9. C与C++中的extern与static、extern C与__cplusplus的作用

    一.概述 以C语言编写的源文件后缀名为.c,以C++语言编写的源文件后缀名为.cpp,C++支持函数的重载,C和C++编译器对函数的编译处理是不完全相同.C++编译后的函数一般是以函数名和形参类型来命 ...

  10. DSP2833x_Device.h头文件中关于extern cregister volatile unsigned int IFR的解释

    看源程序(TMS320F28335)的时候在main函数中看到这样一段: // Disable and clear all CPU interrupts: DINT; IER = 0x0000; IF ...

最新文章

  1. Spring Boot 多模块项目实践(附打包方法)
  2. 用 XGBoost 做 Learning To Rank
  3. SAP Cloud for Customer使用工作流(workflow)实现邮件自动通知功能
  4. 【java基础】zip压缩文件
  5. python中def和return是必须使用的保留字吗_Python 保留字和关键字的用法
  6. C++primer第十章 泛型算法 10.3 定制操作
  7. Visual Studio 2010 SDK
  8. 修改百度搜索结果的标题
  9. 谷歌浏览器下flash背景透明方法
  10. ViewPager VS ViewFilpper
  11. Java异常处理:如何写出“正确”但被编译器认为有语法错误的程序
  12. python编写登录接口_Python之编写登录接口
  13. 软件测试项目实战案例ppt,一个自动测试实战项目案例.ppt
  14. GX Works2使用问题记录
  15. python 打包exe_python打包exe能运行但是没有结果解决方案
  16. ArcGIS地理配准(Georeferencing)详解
  17. shell 中三种引号的用法及区别
  18. 我的世界java版tp_神奇的tp指令 我的世界tp指令的用法
  19. ArcGIS基础:要素转点、要素折点转点与面转线
  20. 8421码5421码2421码余3码

热门文章

  1. 性能测试performance test
  2. java当中jxl合并行、列
  3. LTK5325 2X5.3W双声道升压G类音频功率放大器
  4. SCAU 正n多边形类的定义与使用
  5. 【镜像取证篇】VMware虚拟机配置文件取证
  6. Opencv学习笔记 高动态范围 (HDR) 成像
  7. centos 7.6安装WeADMIN ITOSS步骤
  8. 通过Linux+SNMP+zabbix的实验理解SNMP协议
  9. 汇编语言中的start有什么用?(start只是一个标号,程序不一定非要从这儿才开始执行)
  10. 吉比特2021秋招数据分析笔试