extern总结

extern "C"

在C++引用lua的头文件时,我们总会写成:

extern "C" {
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}

为什么要这么做呢?原因是C++的编译器会对程序中符号进行修饰,这个过程在编译器中叫符号修饰(Name Decoration)或者符号改编(Name Mangling)。同时我们知道C++是能够兼容C的,如果我们有了一个C语言的头文件和其对应的库,在C++中如何使用它呢?在include该头文件的时候当然要加入extern "C",否则按照C++的符号进行符号修饰,那么在库中就会找不到该符号了。

告诉编译器这段代码是以C编译器来编译,底层函数签名就是函数名称,而不是C++那样的函数名+参数,不支持重载的。

 

extern

C++语言支持分离式编译机制,该机制允许将程序分割为若干个文件,每个文件可被独立编译。为了将程序分为许多文件,则需要在文件中共享代码,例如一个文件的代码可能需要另一个文件中中定义的变量。

为了支持分离式编译,C++允许将声明和定义分离开来。变量的声明规定了变量的类型和名字,即使一个名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。定义则负责创建与名字关联的实体,定义还申请存储空间。

如果想声明一个变量而非定义它,就在变量名前添加extern关键字,而且不要显式地初始化变量:

extern int i;  //声明i而非定义
int j;         //声明并定义j

但我们也可以给由extern关键字标记的变量赋一个初始值,但这样就不是一个声明了,而是一个定义:

extern int v = 2;
int v = 2;     //这两个语句效果完全一样,都是v的定义,所以如果编译就会报错

注意: 变量能且只能被定义一次,但是可以被声明多次。

根据C++标准的规定,一个变量声明必须同时满足两个条件才是声明,否则就是定义: 

1、声明必须使用extern关键字;

2、不能给变量赋初值 

extern int a;         //声明

int a;                //定义 
int a = 0;            //定义 
extern int a = 0;     //定义

extern比较普遍的用法是,在一个.c文件中extern声明一个在别的.cpp文件中已经定义的变量(一定要是全局变量),然后在本.cpp文件中操作的就是在那个文件中的变量,相当于跨文件引入一个变量,相当于对.c文件的include。

头文件定义任何变量都是非常业余的行为,因为如果在头文件中定义,如果这个头文件被多个cpp引用(include),会造成重复定义的链接错误。

所以:通常的做法是,在.h文件中用extern声明(不定义)一个变量,然后在想用到这个变量的.cpp文件中用staitc定义这个变量(不定义是没有办法使用的),则该变量只在当前cpp文件中有效,在别的文件中无效如果有两个cpp都定义了这个变量而都没有加static,也会报错。

 

extern 和 static

1、extern 表明该变量在别的地方已经声明过了,在这里要使用那个变量;

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

【注意】

1、extern和static不能同时修饰一个变量

2、static修饰的全局变量声明与定义同时进行

3、static修饰全局变量的作用域只能是本身的编译单元

 

extern 和 const

C++中const修饰的全局常量具有跟static相同的特性,即它们只能作用于本编译模块中,但是const可以与extern连用来声明该常量可以作用于其他编译模块中,如在头文件中写extern const char g_str[]。

然后在cpp中定义:const char g_str[] = "123456"(不同的cpp中可以定义不同的字符串)。

所以当const单独使用时它就与static相同,而当与extern一起时就与extern相同!

 

编译器编译过程

//main.cpp

#include "stdafx.h"
#include "ExternExample.h"

int _tmain(int argc, _TCHAR* argv[])
{
    using namespace std;
    cout << temp << endl;
    
    system("pause");
    return 0;
}

//ExternExample.h

int temp;

1、预编译

所谓预编译,其实就是#include展开和宏展开,上述代码被展开后,main.cpp里面就了int temp这个定义,注意是定义。

2、编译

编译是将刚刚展开之后的.h中的内容和.cpp中的内容作为一个编译单元来进行编译,每个.cpp文件都会按这种方式被编译成一个.obj文件。

3、连接

编译好之后的obj是独立的,需要连接在一起,才能成为一个程序。

【总结】

1、.h头文件中一定不要有定义,只能有声明,定义全部写在.cpp文件里面;

2、在头文件中,需要使用条件编译(windows中可以用#pragma once代替),防止重定义。

#ifndef _EXTERN_EXAMPLE
#define _EXTERN_EXAMPLE

int temp;

#endif

 

参考文章

1、C/C++中extern关键字详解 http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html

2、C/C++ include 条件编译 extern及编译连接浅析 https://www.cnblogs.com/chjtao/p/4673224.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值