C语言之static关键字

C语言之static和extern关键字

1.作用域

标识符可见的区域,访问和重名

由声明的位置所决定

1.1 代码块作用域 Block Scope

  • 花括号 {} 之内

  • 函数形参(不会为函数内同名变量所隐藏)

    ```C
    void myFunction(int x) {
      int x = 10;         // 这里的 x 不会隐藏形参 x
      printf("%d\n", x);  // 输出的仍然是形参 x 的值
    }
    ```
    

1.2 文件作用域 file Scope

所有代码块之外的标识符

自声明开始直到文件尾

  • 函数名
  • include展开可以扩展文件尾,本质上就是字符串替换

1.3 原型作用域 prototype Scope

仅适用于函数原型中声明的参数名,该参数名并非必要的

1.4 函数作用域 Function Scope

仅适用于语句标签,即goto语句

2.链接属性

决定如何处理不同文件中出现的标识符
2.1 None
没有链接属性,多个声明被认为是不同的独立实体
局部变量都是None
2.2 Internal 内部
同一个源文件中所有声明属于同一个实体,不同源文件声明属于不同实体
2.3 External 外部
无论声明多少次都表示同一个实体,即全局变量 Global
全局 VS 局部Local(仅仅是代码块中?)
文件作用域中的标识符默认都是External,增加该关键字具有更好的可读性

3.存储类型

决定变量的生命周期
变量的缺省存储类型取决于声明位置

  • 代码块之外,文件作用域
    • 静态变量 static
    • 静态内存中
    • 执行之前创建,在整个运行期间存在
    • 初始化默认值为0,显示初始化需要使用常量表达式,编译时求值
  • 代码块之内,代码块作用域
    • 自动变量 auto (局部变量 VS auto:static 修改存储类型)
    • 运行时堆栈
    • 执行时创建,退出代码块时销毁
    • 缺省值无效,显示初始化中除了使用const, 声明时初始化和先声明后赋值只有风格之差而无效率之别
  • register修饰的自动变量
    • 提示编译器存储在硬件寄存器中,不一定有效
    • 周期和自动变量一样,不使用地址

4.辨析

全局变量 VS 局部变量

  • 作用域:代码块的内部 VS 外部 (核心区别)
  • 链接属性:extern VS none
  • 存储类型:静态内存 VS 运行时堆栈

静态变量 VS 自动变量

  • 变量对象:
    • static修饰的局部变量(狭义)和全局变量(本质)
    • 自动变量:无static修饰的局部变量
  • 存储位置:
    • 静态变量存储在静态存储区
    • 自动变量存储在栈区
  • 生命周期:
    • 静态变量的生命周期是整个程序的运行期间,从程序开始执行到程序结束
    • 自动变量的生命周期是在其所在的代码块(如函数)被执行期间,当代码块执行结束就被销毁
  • 初始化:
    • 静态变量在编译时初始化,默认值为 0
    • 自动变量在运行时初始化,默认值是未定义的

局部变量缺省为自动类型

  • 运行时才分配存储空间
  • 在堆栈上方便实现递归

static不能修饰函数形参

  • 不改变None链接属性
  • 不可改变存储类型,参数通过堆栈传递

static和Extern关键字

  • 修改链接属性
    • static只对缺省为extern的标识符有效
      • 对 None类型不改变链接属性
    • extern 只对标识符的第一次声明有效

Static 不影响作用域

  • 代码块之外:链接属性改为 Internal
  • 代码块之内:存储类型改为静态内存

5.参考

  • 《C和指针》
    • 3.5 作用域
    • 3.6 链接属性
    • 3.7 存储类型
    • 3.8 static 关键字
    • 3.9 作用域、存储类型示例
  • 《嵌入式C语言的自我修养》
    • 5.3.5 栈和作用域
  • 《C程序设计语言》
    • 1.10 外部变量与作用域
    • 4.3 外部变量
    • 4.4 作用域规则
    • 4.6 静态变量
    • 4.7 寄存器变量
    • 4.8 程序块结构
    • 4.9 初始化