### 6. 存储类型的关键字
**存储类型定义 C 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前**。
存储类型可以用于变量以及较小范围的函数和形式参数的说明。**这一节的内容类似于Java中全局变量和局部变量的概念以及作用域,存储范围等知识点**
#### 变量的性质
C程序中的每个变量都具有以下3个性质。
* **存储期限**。变量的存储期限决定了为变量预留和内存被释放的时间。
* 具有**自动存储期限**的变量在所属块被执行时获得内存单元,并在块终止时释放内存单元,从而会导致变量失去值。
* 具有**静态存储期限**的变量在程序运行期间占有同一个的非储单元,也就允许变量无期限地保留它的值。
* **作用域**。变量的作用域是指可以引用变量的那部分程序文本。变量可以有**块作用域**(变量从声明的地方一直到所在块的末尾都是可见的)或者**文件作用域**(变量从声明的地方一直到所在文件的末尾都是可见的)。
* **链接**。变量的链接确定了程序的不同部分可以共享此变量的范围。
* 具有**外部链接**的变量可以被程序中的几个(或许全部)文件共享。
* 具有**内部链接**的变量只能属于单独一个文件,但是此文件中的函数可以共享这个变量。(如果具有相同名字的变量出现在另一个文件中,那么系统会把它作为不同的变量来处理。)
* **无链接**的变量属于单独一个函数,而且根本不能被共享。
**变量的默认存储期限、作用域和链接都依赖于变量声明的位置**。
* 在块(包指函数体)内部声明的变量具有自动存储期限、块作用域,并且无链接.
* 在程序的最外层(任意块外部)声明的变量有静态存储期限、文件作用域和外部链接。
下面的例子说明了变量i和变量j 的默认性质:
![](https://img.kancloud.cn/c3/8c/c38c6377a77df095533ce963239d4b9d_382x381.png)
**对许多变量而言,默认的存储期限、作用域和链接是符合要求的。当这些性质无法满足要求时,可以通过指定明确的存储类型(auto 、static 、extern和register)来改变变量的性质**。
下面列出 C 程序中可用的存储类:
* auto
* register
* static
* extern
#### auto 存储类
auto 存储类是**所有局部变量默认的存储类**。
```
int month;
auto int month;
```
上面定义了两个带有相同存储类,auto 只能用在函数内,即 auto 只能修饰局部变量。
#### register 存储类
**register 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 '&' 运算符(因为它没有内存位置)**。
```
register int miles;
```
寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,**定义 register并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制**。
#### static 存储类
**static 存储类指示编译器在程序的生命周期内保持局部变量的存在**,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,**使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内**。
**全局声明的一个 static 变量或方法可以被任何函数或方法调用,只要这些方法出现在跟 static 变量或方法同一个文件中**。
例子:
```
//函数声明
void func1(void);
static int count = 10; //全局变量 - static 默认的
void main() {
while (count--) {
func1();
}
}
void func1(void) {
// 'thingy' 是 'func1' 的局部变量 - 只初始化一次
// * 每次调用函数 'func1' 'thingy' 值不会被重置。
static int thingy = 5;
thingy++;
printf("thingy 为 %d, count 为 %d \n", thingy, count);
}
```
输出:
```
thingy 为 6, count 为 9
thingy 为 7, count 为 8
thingy 为 8, count 为 7
thingy 为 9, count 为 6
thingy 为 10, count 为 5
thingy 为 11, count 为 4
thingy 为 12, count 为 3
thingy 为 13, count 为 2
thingy 为 14, count 为 1
thingy 为 15, count 为 0
```
实例中 count 作为全局变量可以在函数内使用,thingy 在局部使用 static 修饰后,不会在每次调用时重置。
#### extern 存储类
extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候,如下所示:
第一个文件 ndk_day1.c
```
#include //stdio.h 是一个头文件(标准输入输出头文件),#include 是一个预处理命令,用来引入头文件。
#include "support.h" //引入自己的头文件
int main() {
int sum = add(2, 5);
printf("extern 使用 :%d", sum);
}
```
声明 support.h 头文件
```
//
// Created by 阳坤 on 2019/12/13.
//
#ifndef NDK_SAMPLE_SUPPORT_H
#define NDK_SAMPLE_SUPPORT_H
#endif //NDK_SAMPLE_SUPPORT_H
extern int add(int num1,int num2);
```
头文件的实现 support.c
```
int add(int num1,int num2){
return num1 * num2;
}
```
输出:
```
extern 使用 :10
```
- 前言
- JNI基础知识
- C语言知识点总结
- ①基本语法
- ②数据类型
- 枚举类型
- 自定义类型(类型定义)
- ③格式化输入输出
- printf函数
- scanf函数
- 编程规范
- ④变量和常量
- 局部变量和外部变量
- ⑤类型转换
- ⑥运算符
- ⑦结构语句
- 1、分支结构(选择语句)
- 2、循环结构
- 退出循环
- break语句
- continue语句
- goto语句
- ⑧函数
- 函数的定义和调用
- 参数
- 函数的返回值
- 递归函数
- 零起点学通C语言摘要
- 内部函数和外部函数
- 变量存储类别
- ⑨数组
- 指针
- 结构体
- 联合体(共用体)
- 预处理器
- 预处理器的工作原理
- 预处理指令
- 宏定义
- 简单的宏
- 带参数的宏
- 预定义宏
- 文件包含
- 条件编译
- 内存中的数据
- C语言读文件和写文件
- JNI知识点总结
- 前情回顾
- JNI规范
- jni开发
- jni开发中常见的错误
- JNI实战演练
- C++(CPP)在Android开发中的应用
- 掘金网友总结的音视频开发知识
- 音视频学习一、C 语言入门
- 1.程序结构
- 2. 基本语法
- 3. 数据类型
- 4. 变量
- 5. 常量
- 6. 存储类型关键字
- 7. 运算符
- 8. 判断
- 9. 循环
- 10. 函数
- 11. 作用域规则
- 12. 数组
- 13. 枚举
- 14. 指针
- 15. 函数指针与回调函数
- 16. 字符串
- 17. 结构体
- 18. 共用体
- 19. typedef
- 20. 输入 & 输出
- 21.文件读写
- 22. 预处理器
- 23.头文件
- 24. 强制类型转换
- 25. 错误处理
- 26. 递归
- 27. 可变参数
- 28. 内存管理
- 29. 命令行参数
- 总结
- 音视频学习二 、C++ 语言入门
- 1. 基本语法
- 2. C++ 关键字
- 3. 数据类型
- 4. 变量类型
- 5. 变量作用域
- 6. 常量
- 7. 修饰符类型
- 8. 存储类
- 9. 运算符
- 10. 循环
- 11. 判断
- 12. 函数
- 13. 数学运算
- 14. 数组
- 15. 字符串
- 16. 指针
- 17. 引用
- 18. 日期 & 时间
- 19. 输入输出
- 20. 数据结构
- 21. 类 & 对象
- 22. 继承
- 23. 重载运算符和重载函数
- 24. 多态
- 25. 数据封装
- 26. 接口(抽象类)
- 27. 文件和流
- 28. 异常处理
- 29. 动态内存
- 30. 命名空间
- 31. 预处理器
- 32. 多线程
- 总结
- 音视频学习 (三) JNI 从入门到掌握
- 音视频学习 (四) 交叉编译动态库、静态库的入门学习
- 音视频学习 (五) Shell 脚本入门
- 音视频学习 (六) 一键编译 32/64 位 FFmpeg 4.2.2
- 音视频学习 (七) 掌握音频基础知识并使用 AudioTrack、OpenSL ES 渲染 PCM 数据
- 音视频学习 (八) 掌握视频基础知识并使用 OpenGL ES 2.0 渲染 YUV 数据
- 音视频学习 (九) 从 0 ~ 1 开发一款 Android 端播放器(支持多协议网络拉流/本地文件)
- 音视频学习 (十) 基于 Nginx 搭建(rtmp、http)直播服务器
- 音视频学习 (十一) Android 端实现 rtmp 推流
- 音视频学习 (十二) 基于 FFmpeg + OpenSLES 实现音频万能播放器
- 音视频学习 (十三) Android 中通过 FFmpeg 命令对音视频编辑处理(已开源)