搜索
您的当前位置:首页正文

C++中的extern声明变量详解

2024-01-04 来源:易榕旅网
C++中的extern声明变量详解

extern声明变量⽆外乎如下两种:1、声明全局变量2、声明函数

今天我们只谈extern,什么const、static之类等等与之相关或不相关的⼀律忽略,下⾯就分别对以上两种情况⼀⼀讲解声明和定义

既然提到extern声明变量,那我们就必须搞清楚声明和定义的区别。

这⾥我们将普通数据变量和函数统称变量。从内存分配⾓度来说,声明和定义的区别在于声明⼀个变量不会分配内存,⽽定义⼀个变量会分配内存。⼀个变量可以被声明多次,但是只能被定义⼀次。

基于以上前提,我们可以把声明和定义类⽐为指针和内存的关系。我们知道,指针其实就是指向内存的⼀个符号,变量的定义就好⽐⼀块内存区域,⽽声明就好⽐它的指针,可以有多个指针指向同⼀个内存区域,⽽⼀个指针只能指向⼀个内存区域,这样就很好理解为什么变量只能被定义⼀次,如果被定义多次,那就会分配多个内存,这样你通过变量的声明到底去找哪块内存区域呢,这会是个问题。

对于数据来说,声明和定义往往是同时存在的,⽐如下⾯的⼀⾏语句复制代码 代码如下:int data;

这样既声明了data同时也定义了data,怎样做到只声明⽽不定义呢,⽤extern就可以了复制代码 代码如下:extern int data;

对于函数来说,声明和定义就很容易区分了,⼀般我们会将声明放在头⽂件⽽将定义放在源⽂件⾥复制代码 代码如下:void hello();

这是⼀个函数的声明,⽽复制代码 代码如下:void hello() {

printf(\"hello world!\\n\"); }

这是⼀个函数的定义。当然,函数的声明和定义也可以同时发⽣,如果我们没有头⽂件⽽只有源⽂件,并且在源⽂件⾥并没有void hello();这样的语句,那么这个函数的声明和定义就同时发⽣了,此时如果我们在原⽂件⾥想要调⽤函数hello(),你调⽤的代码必须在函数定义之后。

其实上⾯的要点只在于⼀句话:使⽤变量之前必须声明,声明可以有多次,⽽定义只能有⼀次。记住这句话,后⾯的就都很容易理解了。extern声明全局变量

我们先来看如下例⼦,现有三个⽂件:test.h, test.cpp, main.cpp,其中main.cpp和test.cpp需要共享⼀个变量g_name,三个⽂件的内容如下复制代码 代码如下:/* test.h */

#ifndef _TEST_H_ #define _TEST_H_

#include

std::string g_name; void hello();

#endif

/* test.cpp */

#include #include \"test.h\"

void hello() {

printf(\"hello %s!\\n\}

/* main.cpp */ #include \"test.h\"

std::string g_name;

int main() {

g_name = \"Handy\"; hello(); return 0; }

三者关系为,test.cpp包含了test.h,main.cpp也包含了test.h,这⾥的包含其实就是include。我们执⾏编译命令复制代码 代码如下:g++ main.cpp test.cpp

编译报错redefinition of 'g_name',说的是g_name被重定义了

我们看⼀下g_name出现的地⽅,⼀个是在test.h⾥,⼀个是在main.cpp⾥,两条语句都是std::string g_name,前⾯我们已经说过,这样的⽅式既声明也定义了变量,那g_name是如何被重定义的呢,⾸先我们需要理解include的含义,我们可以将include⼀个头⽂件理解为在该⾏展开头⽂件⾥的所有代码,由于main.cpp包含了test.h,我们在那⼀⾏将test.h的内容展开,就会发现main.cpp⾥有两句std::string g_name;所以在main.cpp⾥,g_name被定义了两次。

由于我们可以将include头⽂件理解为展开代码,所以编译的时候其实不需要指定头⽂件,只需要源⽂件就够了。需要注意的是,重定义并不是指在同⼀个原⽂件⾥定义多次,⽽是指在整个代码空间⾥,⽐如上⾯的例⼦是就是指在test.cpp和main.cpp⾥,其实上⾯的例⼦⾥g_name是被重定义了三次,其中test.cpp⾥⼀次,main.cpp⾥两次。

那上⾯重定义的问题怎么解决呢,很简答,将test.h⾥的std::string g_name;改为extern std::string g_name;就可以了,由于extern语句只声明变量⽽不定义变量,因此test.cpp和main.cpp展开头⽂件后,也只是将g_name声明了两次,⽽真正的定义还是在main.cpp⾥extern声明函数

还是上⾯的例⼦,我们怎么在main.cpp⾥不包含头⽂件就可以调⽤hello函数呢,既然今天的主题是extern,不⽤提醒也知道,使⽤extern就可以了,代码如下复制代码 代码如下:

/* test.cpp */

#include #include

// 声明g_name

extern std::string g_name;

// 声明和定义void hello() void hello() {

printf(\"hello %s!\\n\}

/* main.cpp */ #include

// 声明和定义g_name std::string g_name;

// 声明void hello() extern void hello();

int main() {

g_name = \"Handy\" hello(); return 0; }

注意这⾥⽤到extern声明变量和函数两种场景,我分别在语句后⾯做了注释。编译命令如下复制代码 代码如下:g++ main.cpp test.cpp

这⾥我们并没有⽤到头⽂件,但是依然可以在不同⽂件间共享变量和函数,这⼀切都是extern的功劳!总结

要了解extern主要搞清以下⼏个概念:

1、声明和定义的区别。全局代码空间⾥,变量可以有多个声明,但只能有⼀个定义 2、include头⽂件等同于展开头⽂件⾥的代码

了解了以上两点,再来分析extern的⽤法,是不是就会清晰很多了

因篇幅问题不能全部显示,请点此查看更多更全内容

Top