云计算百科
云计算领域专业知识百科平台

新手必踩坑:extern 到底是声明还是定义?

前言:

很多刚学 C++ 的同学,学到extern和全局变量的时候直接懵了:

extern int a;、extern int a=10;、int a;,长得差不多,为什么有的是声明、有的是定义?

很多教材会把它们叫做引用性声明、定义性声明,术语一多更容易混淆。

这篇我们从内存分配的角度,把规则、例子、坑点一次性讲清楚。

🎃

 

前置说明: 

  • 引用性声明 = 单纯声明:只告诉编译器有这个变量,不分配内存
  • 定义性声明 = 变量定义:为变量开辟内存,分配内存 C++ 标准里,定义本身属于声明的一种;学习时我们习惯把「单纯声明」和「定义」分开理解。

✅ 核心判断口诀

extern后面不带= → 单纯声明;

只要有=初始化,或者全局直接写int a; → 定义。 判断本质:会不会分配内存。

一、三种写法逐条拆解

1. extern int num1; —— 引用性声明(单纯声明)

extern int num1;

特点:

  • 固定格式:extern 类型 变量名;,不能写初始化=
  • 不分配内存,仅通知编译器:num1是全局 int 变量,它在别处已经定义好了
  • 位置不限:文件头部、函数外面、甚至 main 函数内部都可以写
  • 允许多次书写:多个 cpp 文件都可以写这条声明,没有次数限制
  • 用途:跨文件使用全局变量时,用来引用别的文件里已经定义好的变量
  • 类比:和函数声明 void print(int); 逻辑一样,只告诉编译器 “有这个东西”,没有实体。

    2. extern int num1 = 10; —— 定义性声明(定义)

    extern int num1 = 10;

    ⭐只要带上=初始化,前面的 extern 直接失效,它不再是声明,是定义!

    特点:

  • 分配内存,同时给变量赋值 10
  • 整个项目只能写一次(ODR 单定义规则,重复定义直接链接报错)
  • 必须写在全局区域(函数外面),不能写进函数内部
  • 3. int num1;(写在全局,函数外部)—— 定义性声明(定义)

    int num1;

    特点:

  • 省略 extern,放在全局区,就算不赋值,依然是定义
  • 分配内存,编译器自动初始化为 0
  • 整个项目只能写一次
  • 重要区分:如果写在函数内部,它就变成局部变量定义,不属于全局变量这套规则,不会自动初始化为 0,而是系统随机给一个值
  • 写法本书叫法通俗叫法是否分配内存允许出现次数附加要求
    extern int num1; 引用性声明 单纯声明 ❌ 不分配 ✅ 可以多次 不能写=初始化
    extern int num1 = 10; 定义性声明 定义 ✅ 分配 ❌ 仅 1 次 必须带初始化
    int num1;(全局) 定义性声明 定义 ✅ 分配 ❌ 仅 1 次 写在全局,默认初始 0

    二、同文件的省略规则

    如果全局变量定义写在前,使用在后,并且在同一个.cpp文件里:extern 引用性声明可以省略。

    示例 1:定义在前,无需声明

    #include <iostream>
    using namespace std;
    int num1 = 10; // 全局定义
    int main()
    {
    cout << num1; // 直接使用,不需要extern声明
    return 0;
    }

    示例 2:定义在后,需要 extern 声明

    #include <iostream>
    using namespace std;
    int main()
    {
    extern int num1; // 必须写引用性声明,编译器才能识别num1
    cout << num1;
    return 0;
    }
    int num1 = 10; // 全局定义写在main后面

    三、跨文件完整演示代码(最常用场景)

    文件 1:a.cpp(定义)

    #include <iostream>
    using namespace std;
    // 下面三种定义写法,只能选一个,不能同时写
    // int num1 = 10;
    // extern int num1 = 10;
    int num1; // 全局定义,默认初始值0

    文件 2:b.cpp(使用这个全局变量,只写引用性声明)

    #include <iostream>
    using namespace std;

    // 引用性声明:告诉编译器,num1在别的cpp里面定义好了
    extern int num1;

    int main()
    {
    cout << "一开始 num1 = " << num1 << endl;
    num1 = 20;
    cout << "修改后 num1 = " << num1 << endl;
    return 0;
    }

    四、文末小结

  • 引用性声明:extern 变量;,无初始化,只做告知,不分配内存,可多处写;
  • 定义性声明(定义)两种形式:extern int a=xx; 或者全局写 int a;;
  • 定义只能一份,声明可以多份;
  • 同文件定义在前、使用在后,extern 声明可以省略。
  • 希望可以帮助到大家,感谢观看,如果觉得文章对你有帮助的话,请点赞收藏关注支持一下博主😍,如有不足请指点,我及时改正!👻一起加油!嘻嘻😜

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 新手必踩坑:extern 到底是声明还是定义?
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!