C 语言中的变量作用域及修饰符

变量作用域

作用域

作用域是用来限定变量发挥作用的区域,{}是变量作用域的限定符。

变量

局部变量

  • 局部变量的作用范围是局部的
  • 一般情况下,{} 内声明的变量都是局部变量
  • 局部变量作用域起始于定义处,终止于大括号的结束
  • 局部变量未被赋值的时候,初始化为随机值

全局变量

  • 全局变量的作用范围是全局的,在本文件的任何地方都可以进行使用
  • 一般情况下,{} 外声明的变量都是全局变量
  • 全局变量作用域起始于定义处,终止于本文件结束
  • 全局变量未被赋值的时候,初始化为 0

作用域叠加

当不同位置定义的变量作用域发生重叠的时候,会发生局部屏蔽现象:

  • 全局变量与局部变量发生作用域叠加时,以局部变量为准
  • 局部变量与局部变量发生作用域叠加时,在次一级的局部变量被定义之前以上一级作用域的局部变量为准
  • 局部变量与局部变量发生作用域叠加时,在次一级的局部变量被定义之后以当前作用域的局部变量为准
  • 全局变量未被屏蔽或屏蔽消除后,以全局变量为主
#include <stdio.h>

int a = 1;

void show()
{
    int a = 2;
    printf("a = %d\n",a);
}

int main()
{
    printf("a = %d\n",a);
    int a = 3;
    printf("a = %d\n",a);
    show();
    printf("a = %d\n",a);

    {
        printf("a = %d\n",a);
        int a = 4;
        printf("a = %d\n",a);
    }
    printf("a = %d\n",a);

    return 0;
}

结果为:

a = 1
a = 3
a = 2
a = 3
a = 3
a = 4
a = 3
  • 第一次打印,全局变量未被屏蔽,没有定义局部变量,全局变量有效,打印 a =1
  • 第二次打印,全局变量被屏蔽,当前局部变量有效,打印 a =3
  • 第三次打印,全局变量被屏蔽,当前局部变量为自定义函数中的局部变量,打印 a = 2
  • 第四次打印,全局变量被屏蔽,自定义函数中的局部变量被释放,打印 a = 3
  • 第五次打印,全局变量被屏蔽,当前 {} 中的局部变量未定义,以上一级作用域局部变量为主,打印 a = 3
  • 第六次打印,全局变量被屏蔽,当前 {} 中的局部变量定义,以当前作用域局部变量为主,打印 a = 4
  • 第七次打印,全局变量被屏蔽,当前局部变量有效,打印 a = 3

命名污染

  • 一般情况下,同一作用域下的变量如果进行重定义会发生报错
  • 不同作用域下的局部变量如果重定义一般不会有什么问题,因为作用域是局部的(如同上面程序,只要自己搞清楚就可以)
  • 而全局变量因为作用域是局部的,相同的变量名往往会发生命名污染
  • 命名污染是指在全局作用域内的变量发生的重定义现象,在大型团队开发任务中需要严格注意
  • 为了避免这种现象,要少用全局变量,或者是对全局变量进行统一管理

生命周期

  • 作用域表明的是变量的作用范围,可以类比为空间概念
  • 生命周期表明的是程序执行时变量的存在范围,可以类比为时间概念
  • 作用域内的变量一定存在于其生命周期内
  • 但生命周期内的变量却不一定能够使用,比如被屏蔽
  • 局部变量的生命周期与其所在的 {} 一致,用完即销
  • 全局变量的生命周期与所在进程一致,进程结束也就随之消失
  • main 函数中的变量准确地说应该算是局部变量,但是其生命周期却是与进程一致

修饰符

修饰符用来修饰变量,能够改变其生命周期或存储区域。格式为:

modifier datatype  var;

auto

  • auto 只能用来修饰局部变量,可以省略
  • 局部变量若无其它修饰符,则默认为 auto,也就是说,平常使用的变量大部分都是 auto 修饰的
  • 特点:随用随开,用完即销

register

  • 只能修饰局部变量
  • 一般情况下,是将内存中的变量放到 CPU 寄存器中存储,能够提高访问速度
  • 但 CPU 寄存器数目有限,在程序优化阶段通常会被优化为普通的 auto 修饰的变量

extern

  • 只能用来修饰全局变量
  • 使用本文件之外定义的变量需要加 extern 修饰,否则就会造成重定义
  • extern 修饰的变量只能使用,不能重新赋值
//main.c
#include <stdio.h>

extern int b;

int main()
{
    int a = 1;

    printf("a = %d\n",a);
    printf("b = %d\n",b);

    return 0;
}
//else.c
int b = 2;

结果为:

a = 1
b = 2
  • C 文件是自顶而下,逐个编译的
  • 使用其它文件中的变量而不进行 extern 修饰,则会编译出错
  • 用 extern 修饰其它文件中的变量进行使用,则编译通过并在链接过程中重新进行链接

static

static 修饰局部变量时:

  • 会更改局部变量的生命周期,使其与进程一致
  • static 修饰的局部变量如果未初始化,会被初始化为 0

static 修饰全局变量时:

  • 会限制该变量的外延性,使其成为只能在本文件内部使用的全局变量
  • 避免了命名污染
发布了77 篇原创文章 · 获赞 5 · 访问量 4881

猜你喜欢

转载自blog.csdn.net/SAKURASANN/article/details/104508178