引言

在 C/C++ 中,不少人把声明(declaration)和定义(definition)搞混淆,下面就通过这篇文章,来详细阐述一下这两者的区别。

声明和定义的概念

声明(declaration):是指出存储类型,并给存储单元指定名称。

定义(definition):是分配内存空间,还可为变量指定初始值。

所以,根据这个定义,我们不难发现:

  • 声明可以看做一种规范(规定存储类型和存储单元的名称),所以我们可以在不同的文件进行多次声明,而不会产生冲突。

  • 而定义会对声明的内容进行分配存储空间和初始化等等操作,这个过程是不可以多次重复进行的。

规范

在 C/C++ 的规范中,我们将声明的内容放入头文件 (.h) 中,并且使用 #ifndef的方式来避免重复包含,而将定义的内容放在源文件 (.c, .cpp) 中,所以,我们应该只include头文件,而不应该去引入源文件,这样就能避免重复定义而导致在编译过程中无法进行链接

具体例子:声明

注:本文就不细讲 extern的具体用法和注意事项了,请自行补充。

假设我们有3个文件,分别是:test1.htest2.hmain.cpp

  1. 变量声明

    1
    2
    3
    4
    5
    6
    7
    8
    // "test.h"
    extern int num; // 这里只是声明了一个变量num,并不是定义变量

    // "test2.h"
    extern int num; // 继续声明变量,允许

    // "main.cpp"
    extern int num; // 仍然可以声明
  2. 函数声明

    1
    2
    3
    4
    5
    6
    7
    8
    // "test.h"
    void foo(int, double); // 声明一个函数,并没有定义函数

    // "test2.h"
    void foo(int, double); // 继续声明

    // "main.cpp"
    void foo(int, double); // 仍然可以声明
  3. 类声明

1
class A;  // 声明一个类,并没有进行具体定义

上面三种方式均为声明,并不是定义,即变量不会分配内存,函数和类也不会在代码区分配内存。


具体例子:定义

仍然是上面三个文件。

1
2
// main.cpp
int num; // 这里既是声明,又是定义,分配了内存,但是没有初始化

注意,一个变量可以有多个声明,但只能有一个定义,所以我们为了在所有头文件中共享一个变量,可以这么操作:

1
2
3
4
5
6
7
8
// "test1.h"
extern int num; // 表示需要引用num,所以使用extern声明

// "test2.h"
extern int num;

// "main.cpp"
int num = 1; // 声明并定义一个全局变量,且初始化为 1

这样,假设我们有一个源文件test1.cpp

1
2
3
4
#include "test1.h"
void foo() {
std::cout << num << std::endl; // 这样,我们就可以使用变量 num
}