extern用法详解:

1. 声明外部实体

声明外部全局变量或对象,一般用于头文件中,表示在其它编译单元内定义的变量,链接时进行外部链接,如: 
extern int ivalue; 
此时的extern是必须的,省略了extern编译器将视为定义而不是声明,一般地在源代码中定义变量并进行初始化,在头文件中使用extern声明变量。

类似地用于声明外部全局函数,表示该函数在其它编译单元中定义,如: 
extern void func( void ); 
此时的extern可以省略。

2. 声明函数的编译和链接方式

extern 后可以跟"C"或"C++"用于声明全局函数的编译和链接方式,例如:

 extern "C" void add( int a, int b);
extern "C++" void sum(int* ia, int leng);
void sum(int* ia, int leng);

其中的extern "C++"可以省略,它是在C++中默认的链接方式,即后面两种声明方式是等效的。这种声明有两种含义:首先,声明这些函数使用外部链接方式,其实现不在本编译单元之内;另一种含义,则是告诉编译器编译方式,如extern "C"则是告诉编译器使用C语言的编译方式编译该函数。

C++支持函数重载,所以参数不同在编译后生成的函数名也不同,如:

int max(int a, int b);
int max(float a, float b);

在编译时生成的函数名可能分别为_max_int_int、_max_float_float,通过在函数名后加上参数类型来区分不同的函数,如果使用C语言方式,则生成的函数名中不包含参数信息,只生成_max,所以无法实现重载,也就是说在extern “C”中不能出现函数名重载,例如:

 extern "C" {
int max(int a, int b);
int max(float a, float b);
}

非法,编译器将报错。而C++标准中并没有定义extern “C”与extern “C++”的具体实现方式,不同编译器生成的符号规则可能不同。

需要注意的是,如果函数声明使用了extern "C",则函数定义必须使用C编译器编译,或者使用extern "C"来修改函数的编译方式,一般地将extern "C"声明的函数的定义所在的源程序扩展名使用.c即可,而C++代码放在.cpp文件中。如果将extern "C"声明的函数实现也放在.cpp中,则需要使用extern "C"来声明函数编译方式,例如:

 extern "C" {
int max( int a, int b)
{
return a > b ? a : b;
}
}

只有在C++中使用C语言的库或者两种语言混合编程的时候才会用到extern "C",而在C语言中是不支持extern "C"的,所以为了头文件通用,需要使用宏来控制,例如:

 #ifndef MAX_H // 防止重复引用
#define MAX_H
#ifdef __cplusplus
extern "C" {
#endif
int max (int a, int b);
#ifdef __cplusplus
}
#endif
#endif

其中__cplusplus为C++定义的宏,凡是C++的编译器都定义了该预编译宏,通过它来检测当前编译器是否使用的是C++编译器。

extern和static比较:

(1)extren表明该变量在别的地方已经定义过,而在这里要使用那个变量。

(2)static表示静态的变量,分配内存时,存储在静态区,不存储在栈上面。

static 作用范围是内部连接的关系, 和extern有点相反.它和对象本身是分开存储的,extern也是分开存储的,但是extern可以被其他的对象用extern 引用,而static 不可以,只允许对象本身用它。

具体差别:首先,static与extern是一对“水火不容”的家伙,也就是说extern和static不能同时修饰一个变量;其次,static修饰的全局变量声明与定义同时进行,也就是说当你在头文件中使用static声明了全局变量后,它也同时被定义了;最后,static修饰全局变量的作用域只能是本身的编译单元,也就是说它的“全局”只对本编译单元有效,其他编译单元则看不到它,如:

(1)test.h:

 #ifndef TEST1H
#define TEST1H
static char g_str[] = "";
void fun1();
#endif

(2)test1.cpp:

 #include "test.h"
void fun1()
{
cout << g_str << endl;
}

(3)test2.cpp

 #include "test.h"
void fun2()
{
cout << g_str << endl;
}

以上两个编译单元可以连接成功, 当你打开test1.obj时,你可以在它里面找到字符串"123456",同时你也可以在test2.obj中找到它们,它们之所以可以连接成功而没有报重复定义的错误是因为虽然它们有相同的内容,但是存储的物理地址并不一样,就像是两个不同变量赋了相同的值一样,而这两个变量分别作用于它们各自的编译单元。 也许你比较较真,自己偷偷的跟踪调试上面的代码,结果你发现两个编译单元(test1,test2)的g_str的内存地址相同,于是你下结论static修饰的变量也可以作用于其他模块,但是我要告诉你,那是你的编译器在欺骗你,大多数编译器都对代码都有优化功能,以达到生成的目标程序更节省内存,执行效率更高,当编译器在连接各个编译单元的时候,它会把相同内容的内存只拷贝一份,比如上面的"123456", 位于两个编译单元中的变量都是同样的内容,那么在连接的时候它在内存中就只会存在一份了,如果你把上面的代码改成下面的样子,你马上就可以拆穿编译器的谎言:

(1)test1.cpp:

 #include "test.h"
void fun1()
{
g_str[] = 'a';
cout << g_str << endl;
}

(2)test2.cpp

 #include "test.h"
void fun2()
{
cout << g_str << endl;
}

(3)main

 void main()
{
fun1(); // a23456
fun2(); //
}

这个时候你在跟踪代码时,就会发现两个编译单元中的g_str地址并不相同,因为你在一处修改了它,所以编译器被强行的恢复内存的原貌,在内存中存在了两份拷贝给两个模块中的变量使用。正是因为static有以上的特性,所以一般定义static全局变量时,都把它放在原文件中而不是头文件,这样就不会给其他模块造成不必要的信息污染,同样记住这个原则吧!

extern和const比较:

C++中const修饰的全局常量据有跟static相同的特性,即它们只能作用于本编译模块中,但是const可以与extern连用来声明该常量可以作用于其他编译模块中, 如extern const char g_str[];
然后在原文件中别忘了定义:     const char g_str[] = "123456";

所以当const单独使用时它就与static相同,而当与extern一起合作的时候,它的特性就跟extern的一样了!所以对const我没有什么可以过多的描述,我只是想提醒你,const char* g_str = "123456" 与 const char g_str[] ="123465"是不同的, 前面那个const 修饰的是char *而不是g_str,它的g_str并不是常量,它被看做是一个定义了的全局变量(可以被其他编译单元使用), 所以如果你像让char*g_str遵守const的全局常量的规则,最好这么定义const char* const g_str="123456"。

[C/C++] extern关键字详解以及与static、const区别的更多相关文章

  1. 【转载】C/C++中extern关键字详解

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...

  2. C/C++中extern关键字详解

    转自:http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html 1 基本解释:extern可以置于变量或者函数前,以标示变 ...

  3. c++extern关键字详解

    1 基本解释 :extern可以置于变量或者函数 前,以标示变量或者函数的定义在别的文件中 ,提示编译器遇到此变量和函数时在其他模块中寻找其定义 .此外extern也可用来进行链接指定. 也就是说ex ...

  4. C/C++中extern关键字详解(转)

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...

  5. C++/C extern关键字详解 EntryPointNotFoundException处理

    最近在弄C#帮公司做一个图像识别的功能,用到了第三方的dll,在调用dll过程中就出现了一个问题.EntryPointNotFoundException异常.遇到这种异常,很大可能就是在生成dll时函 ...

  6. extern关键字详解

    基本理解 extern放在变量或者函数之前,表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义. extern有两个作用 1.当它与"C"一起连 ...

  7. Objective-C 实用关键字详解1「面试、工作」看我就 🐒 了 ^_^.

    在写项目 或 阅读别人的代码(一些优秀的源码)中,总能发现一些常见的关键字,随着编程经验的积累大部分还是知道是什么意思 的. 相信很多开发者跟我当初一样,只是基本的常用关键字定义属性会使用,但在关键字 ...

  8. extern用法详解

    1 基本解释 extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义. 另外,extern也可用来进行链接指定. 2 问题:ext ...

  9. c++ --> extern "C" {}详解

    extern "C" {}详解 extern "C"的真实目的是实现类C和C++的混合编程.在C++源文件中的语句前面加上extern "C" ...

随机推荐

  1. Django从请求到返回流程

    图1:流程图 1. 用户通过浏览器请求一个页面2.请求到达Request Middlewares,中间件对request做一些预处理或者直接response请求3.URLConf通过urls.py文件 ...

  2. deepin15.7下使用apt安装mysql5.7不显示root密码设置的解决方法

    在安装MySQL的过程中,并没有要求设置root账户密码的步骤,导致很多人无法使用root账户登录 这个问题早已有解决方案,笔者在deepin15.7下安装也遇到同样问题,只是做一个简单的记录 解决思 ...

  3. 邮件发送失败问题:Sending the email to the following server failed : smtp.qiye.163.com:25

    [邮件发送错误] : Sending the email to the following server failed : smtp.qiye.163.com:25, {}org.apache.com ...

  4. bootstrap-daterangepicker插件运用

    引入:daterangepicker.css.daterangepicker.js.moment.js.moment.min.js 链接:https://files.cnblogs.com/files ...

  5. 解决 Android sdk content loader 0%

    第一次遇到这种情况,真的很头痛,没办法 ,是问题就要解决,在网上找了一些方法,归纳了下来. 方法一(关闭后重启): 遇到Eclipse右下角一直显示“Android sdk content loade ...

  6. PHP----composer安装和TP5验证码类

    妈的,想用TP5做个项目,用到登录验证码了,结果煞笔TP5不内置了,需要用Composer,用吧,来下载 1.安装Composer 1.1 更新 sudo apt-get update 1.2 安装w ...

  7. PHP中的mysql_unbuffered_query与mysql_query的区别

    对于mysql_query大家都很熟悉,下面先简单介绍下mysql_unbuffered_query mysql_unbuffered_query (PHP 4 >= 4.0.6, PHP 5) ...

  8. C语言实例解析精粹学习笔记——39(简单的文本编辑器)

    实例说明: 编辑一个简单的单行文本编辑器,编辑命令有以下几种:(E.Q.R.I.D) 只有自己在完全空白的情况下编写出来的程序,才是真正自己会的程序,现在所做的,不过是程序的搬运工,把书上的程序搬到网 ...

  9. RedHat6.4 安装yum源

    主要参考: http://blog.itpub.net/25313300/viewspace-708509/ http://blog.sina.com.cn/s/blog_50f908410101ct ...

  10. CSS3实现3d菜单翻转

    transform-style:flat | preserve-3d: 3d透视属性.针对子元素如何在3d空间相对其父元素渲染,这个属性声明在父元素上,并且他的子元素使用了transform才会有效. ...