简单说,教你彻底理解C++中声明和定义的区别!

变量声明与定义的关系。

为了能够把程序分成多个逻辑部分来进行编写。C++支持分离式编译1机制,这个机制使我们可以将程序分割成若干个文件,每个文件都可以被独立编译。

那我们将一整个程序切割成了多个文件,为了使这些文件联系起来,则肯定需要有一种文件间可以共享代码的方式。例如,一个文件的代码可能需要使用另一个文件中定义的变量。
一个实际的例子是,std::cout 和 std::cin 它们都定义于标准库,却能够被我们写的程序所使用。

为了支持分离式编译,C++将声明与定义区分开来。声明使得名字被程序所知,一个程序如果想要使用别的文件所定义的名字,就要包含对那个名字的声明,而定义是负责创建名字所对应的实体。

变量声明规定了变量的类型与名字,在这一点上定义与之相同,除此之外,定义还申请了变量类型所对应的内存空间,也有可能对变量赋予了初始值。

如果想要声明一个变量而不去定义它,就需要在变量类型前加上extern关键字,而且不要显式的去初始化变量。

extern int a; //声明变量a
int b; //声明并定义b;
extern int c = 5; //定义c,并给c赋初始值5。如果c是全局变量,则会被编译器给予警告,
				  //‘extern’变量有一个初始值。如果是在函数体内部,则会直接报错。

任何初始化了的变量都会成为定义。我们可以给extern的变量加上一个初始值,但这同样也抵消了extern关键字的作用,使这个声明成为了一个定义。在函数体内,初始化一个extern变量将会引发错误。

如果在多个文件中需要用到同样的变量,就必须将变量的声明与定义分开来写。变量的定义必须出现在且只能出现在同一个文件之中,而其他需要用到这个变量的文件,则需要对这个变量进行声明。

一个变量可以被声明无数次,但只能被定义一次。这一点非常重要!!!

函数的声明与定义的关系

函数也是只能被定义一次,但是可以声明多次。与变量不同的是,函数声明不用和变量一样,在自己的返回类型前加extern关键字。函数的声明就是函数定义去掉了函数体转而用一个分号代替而已。
声明一个函数大致的模版:

返回类型 函数名 形参列表 ;

后面返回来写这篇文章时,我产生了一个思考,到底什么是函数只能被定义一次。假如我们将可执行程序的所需要的所有东西都写在一个文件里,那这个时候,函数确实是只能被定义一次。

那如果我们采用的是分离式编译呢?我的想法大概是这样。我们一般是会把所有用到函数的声明写成一个头文件。在最后生成这个可执行文件的时候将这个函数链接进程序中。然后这些函数的实现(定义)我们会分别写成一个个的文件,也是在链接生成可执行程序时,一起被链接进程序里。
而只能被定义一次的意思是,我们链接进函数的定义文件,只能是唯一定义文文件。
再简单点说,就是我们可以定义某一函数的多个版本,写成不同的文件,但最后链接进程序中的,只能是其中的一个。
有点绕,但是我们可以用下面的这个例子去解答。

(base) zoom@songpeifengdeMacBook-Pro project % ls
add.c   add1.c  head.h  main.c  sub.c   sub1.c
(base) zoom@songpeifengdeMacBook-Pro project % gcc -c *.c
(base) zoom@songpeifengdeMacBook-Pro project % gcc add.o sub.o main.o -o app
(base) zoom@songpeifengdeMacBook-Pro project % gcc add1.o sub1.o main.o -o APP
(base) zoom@songpeifengdeMacBook-Pro project % ls
APP     add.c   add.o   add1.c  add1.o  head.h  main.c  main.o  sub.c   sub.o   sub1.c  sub1.o
(base) zoom@songpeifengdeMacBook-Pro project % 

其中add和add1.c是是声明在head.h里的add函数的定义。这样应该算我将这个函数定义了两次,sub同理。
然后我分别将其中一组链接成一个可执行程序,然后去运行,也都运行成功了。

(base) zoom@songpeifengdeMacBook-Pro project % ./app
a = 20, b = 12
a + b = 32
a - b = 8
(base) zoom@songpeifengdeMacBook-Pro project % ./APP 
a = 20, b = 12
a + b = 32
a - b = 8
(base) zoom@songpeifengdeMacBook-Pro project % 

这就足以证明我的理解是对的了。这里如果我将add和add1都链接进程序,我觉得一定会出错,这就意味着我将函数定义两遍了。

(base) zoom@songpeifengdeMacBook-Pro project % gcc add.o add1.o sub.o main.o -o APPP
duplicate symbol '_add' in:
    add.o
    add1.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

可以理论得证!很严谨hh
精炼的总结一下,就是在一个可执行程序之中,函数的定义只能是唯一的。

总结

变量声明与定义的区别在于,声明是让变量的名字和类型被程序所知,而定义比声明多申请了一个内存空间。要想只声明而不定义变量,就需要在变量类型前加上extern关键字。否则就是声明且定义。任何初始化过的变量都是定义。
⚠️注意:这里只是在讲变量的声明与定义的区别。和函数的定义与声明不同。不要混淆了!!!
函数也是只能被定义一次,但是可以声明多次。函数的声明就是函数定义去掉了函数体转而用一个分号代替。

变量和函数都是只能被声明多次,只能被定义一次的。


  1. 分离式编译模式源于C语言,在C++语言中继续沿用。简单地说,分离编译模式是指:一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件连接起来形成单一的可执行文件的过程。 ↩︎

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿宋同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值