一、 extern做变量声明

l  声明externkeyword的全局变量和函数可以使得它们可以跨文件被訪问。

我们一般把全部的全局变量和全局函数的实现都放在一个*.cpp文件中面,然后用一个同名的*.h文件包括全部的函数和变量的声明。如:

/*Demo.h*/
#pragma once
extern inta;
extern intb;
intadd(inta,intb);
/*Demo.cpp*/
#include "Demo.h" /*这句话写或者不写在本例中都行,只是建议不写*/
/*不写不会出问题,写了有些情况下会出问题,以下有解释*/
int a =10;
int b =20; int add(intl,intr)
{
return l +r;
}

假设将Demo.cpp写成了Demo.c,编译器会告诉你说无法解析的外部符号。

由于Demo.c里面的实现会被C编译器处理,然而C++和C编译器在编译函数时存在差异,所以会存在找不到函数的情况。

l  全局函数的声明语句中,keywordextern能够省略,由于全局函数默认是extern类型的。

l 声明和定义

externint a; //属于声明 
externint a = 10; //属于定义,同下

externchar
g_str[]="123456";//这个时候相当于没有extern

假设在一个文件中定义了char g_str[] = "123456";在另外一个文件中必须使用extern char g_str[ ];来声明。不能使用extern char* g_str;来声明。

extern是严格的声明。

且extern char* g_str仅仅是声明的一个全局字符指针。

注:声明能够拷贝n次,可是定义仅仅能定义一次。

二、extern “C”

l  extern "C" 包括双重含义。从字面上就可以得到:首先,被它修饰的目标是“extern”的;其次。被它修饰的目标是“C”的。

被extern "C"限定的函数或变量是extern类型的:

extern是C/C++语言中表明函数和全局变量作用范围(可见性)的keyword,该keyword告诉编译器,其声明的函数和变量能够在本模块或其他模块中使用。

记住。下列语句:

extern int a;

不过一个变量的声明,其并非在定义变量a,并未为a分配内存空间。变量a在全部模块中作为一种全局变量只能被定义一次。否则会出现连接错误。

通常,在模块的头文件里对本模块提供给其他模块引用的函数和全局变量以keywordextern声明。

比如,假设模块B欲引用该模块A中定义的全局变量和函数时仅仅需包括模块A的头文件就可以。这样。模块B中调用模块A中的函数时,在编译阶段,模块B尽管找不到该函数,可是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数。

与extern相应的keyword是static,被它修饰的全局变量和函数仅仅能在本模块中使用。因此。一个函数或变量仅仅可能被本模块使用时。其不可能被extern “C”修饰。

实现C++与C及其他语言的混合编程:

被extern"C"修饰的变量和函数是依照C语言方式编译和连接的。未加extern “C”则依照声明时的编译方式。

l  extern "C"的惯使用方法

(1)在C++中引用C语言中的函数和变量,在包括C语言头文件(如果为cExample.h)时。需进行下列处理:

extern "C"{

#include "cExample.h"

}

而在C语言的头文件里,对其外部函数仅仅能指定为extern类型,C语言中不支持extern"C"声明,在.c文件里包括了extern"C"时会出现编译语法错误。

(2)在C中引用C++语言中的函数和变量时,C++的头文件需加入extern"C",可是在C语言中不能直接引用声明了extern"C"的该头文件。应该仅将C文件里将C++中定义的extern"C"函数声明为extern类型。

三、 extern 和static

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

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

static作用范围是内部连接的关系这和extern有点相反。它和对象本身是分开存储的,extern也是分开存储的。可是extern能够被其它的对象用extern引用,而static不能够,仅仅同意对象本身用它。详细区别首先,static与extern是一对“水火不容”的家伙,也就是说extern和static不能同一时候修饰一个变量。其次。static修饰的全局变量声明与定义同一时候进行。也就是说当你在头文件里使用static声明了全局变量后。它也同一时候被定义了;最后,static修饰全局变量的作用域仅仅能是本身的编译单元,也就是说它的“全局”仅仅对本编译单元有效,其它编译单元则看不到它,如:

/*test1.h*/
#ifndef TEST1H
#define TEST1H
static char g_str[]="123456";
void fun1();
#endif
/*test1.cpp*/
#include "test1.h"
void fun1()
{
cout <<g_str<<endl;
}

/*test2.cpp*/
#include "test1.h"
void fun2()
{
cout <<g_str<<endl;
}

以上两个编译单元能够连接成功。当你打开test1.obj时,你能够在它里面找到字符串"123456"。同一时候你也能够在test2.obj中找到它们。它们之所以能够连接成功而没有报反复定义的错误是由于尽管它们有同样的内容,可是存储的物理地址并不一样,就像是两个不同变量赋了同样的值一样。而这两个变量分别作用于它们各自的编译单元。

或许你比較较真,自己偷偷的跟踪调试上面的代码,结果你发现两个编译单元(test1,test2)的g_str的内存地址同样。于是你下结论static修饰的变量也能够作用于其它模块,可是我要告诉你,那是你的编译器在欺骗你,大多数编译器都对代码都有优化功能,以达到生成的目标程序更节省内存,运行效率更高,当编译器在连接各个编译单元的时候,它会把同样内容的内存仅仅拷贝一份,比方上面的"123456"。位于两个编译单元中的变量都是同样的内容,那么在连接的时候它在内存中就仅仅会存在一份了,假设你把上面的代码改成以下的样子,你立即就能够拆穿编译器的谎言:

/*test1.cpp*/
#include "test1.h"
void fun1()
{
g_str[0]=''a'';
cout <<g_str<<endl;
}
/*test2.cpp*/
#include "test1.h"
void fun2()
{
cout <<g_str<<endl;
}
/*main.cpp*/
void main()
{
fun1();// a23456
fun2();// 123456
}

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

四、extern和const

C++中const修饰的全局常量具有跟static同样的特性,即它们仅仅能作用于本编译模块中,且static修饰的是全局变量,可是const能够与extern连用来声明该常量能够作用于其它编译模块中,如externconst
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"。

深入理解extern使用方法的更多相关文章

  1. js中的回调函数的理解和使用方法

    js中的回调函数的理解和使用方法 一. 回调函数的作用 js代码会至上而下一条线执行下去,但是有时候我们需要等到一个操作结束之后再进行下一个操作,这时候就需要用到回调函数. 二. 回调函数的解释 因为 ...

  2. extern 使用方法具体解释

    在C语言中,修饰符extern用在变量或者函数的声明前,用来说明"此变量/函数是在别处定义的.要在此处引用".(extern能够置于变量或者函数前,以标示变量或者函数的定义在别的文 ...

  3. 【JVM虚拟机】(8)--深入理解Class中--方法、属性表集合

    #[JVM虚拟机](8)--深入理解Class中--方法.属性表集合 之前有关class文件已经写了两篇博客: 1.[JVM虚拟机](5)---深入理解JVM-Class中常量池 2.[JVM虚拟机] ...

  4. 理解 ES6 Generator-next()方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 连续张量理解和contiguous()方法使用,view和reshape的区别

    连续张量理解和contiguous()方法使用,view和reshape的区别 待办 内存共享: 下边的x内存布局是从0开始的,y内存布局,不是从0开始的张量 For example: when yo ...

  6. 理解extern

    extern有两层含义:表示声明和extern C 1.C++分为编译期和运行期,C++是分别单独编译,编译期可认为有三个步骤:a.预编译进行文本替换,将源文件(cpp文件)生成编译单元:b.编译单元 ...

  7. 理解extern char s[100]与extern char *s

    在x.c中定义了一个字符数组 char s[100],在l.c中进行引用extern char s[200], 有些c程序新手经常把它写成extern char *s. 这两种写法的含义一样吗? 首先 ...

  8. extern外部方法使用C#简单样例

    外部方法使用C#简单样例 1.添加引用using System.Runtime.InteropServices; 2.声明和实现的连接[DllImport("kernel32", ...

  9. 百度Android语音识别SDK语义理解与解析方法

    百度语义理解开放平台面向互联网开发人员提供自然语言文本的解析服务,也就是能够依据文本的意图解析成对应的表示. 为了易于人阅读,同一时候也方便机器解析和生成,意图表示协议採用 json 语言进行描写叙述 ...

随机推荐

  1. 【Eclipse】修改java代码不强制重启

    找到tomcat的server.xml文件,修改以下代码,重新发布重启.然后修改java代码就可以不用重启了. 将reloadable=“true”改成reloadable="false&q ...

  2. ognl中的#、%和$

    多学点,谢谢兄弟 原文地址:ognl中的#.%和$作者:百合 ognl中的#.%和$ #.%和$符号在OGNL表达式中经常出现,而这三种符号也是开发者不容易掌握和理解的部分.在这里笔者简单介绍它们的相 ...

  3. Windows Phone 8初学者开发—第17部分:Coding4Fun工具包简介

    原文 Windows Phone 8初学者开发—第17部分:Coding4Fun工具包简介 第17部分:Coding4Fun工具包简介 原文地址:  http://channel9.msdn.com/ ...

  4. python中multiprocessing.pool函数介绍_正在拉磨_新浪博客

    python中multiprocessing.pool函数介绍_正在拉磨_新浪博客     python中multiprocessing.pool函数介绍    (2010-06-10 03:46:5 ...

  5. 【开源框架EGOTableViewPullRefresh的研究】

    EGOTableViewPullRefresh:点击打开链接https://github.com/enormego/EGOTableViewPullRefresh RootViewController ...

  6. JDK1.6官方下载

    JDK1.6官方下载_JDK6官方下载地址:http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin- ...

  7. Python学习-使用matplotlib画动态多图

    最近常常使用matplotlib进行数学函数图的绘制,可是怎样使用matplotlib绘制动态图,以及绘制动态多图.直到今天才学会. 1.參考文字 首先感谢几篇文字的作者.帮我学会了怎样绘制.大家也能 ...

  8. 08-IOSCore - App Store、国际化/本地化

    App Store 1. 帐号身份 0. 有Xcode 写程序,在虚拟机上运行 1. 成为苹果使用者 appleid 验证邮箱 权限: 能下载应用程序 2. 成为苹果开发者 https://devel ...

  9. ActivityGroup相关--getLocalActivityManager() 以及intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)用法

    ActivityGroup简介 1.ActivityGroup的核心就是继承了该类,能够通过getLocalActivityManager()得到一个LocalActivityManager 如,Lo ...

  10. Android 它们的定义View它BounceProgressBar

    转载请注明出处:http://blog.csdn.net/bbld_/article/details/41246247 [Rocko's blog] 之前几天下载了非常久没用了的桌面版酷狗来用用的时候 ...