## 全局变量 & 宏 & 大程序结构
### 全局变量
#### 认识 全局变量
- 定义在函数外的变量就是全局变量
- 全局变量具有全局的生存期和作用域
- 它们与任何函数无关
- 任何函数(定义在全局变量后的的函数)内部都可以使用它们
例如:
```c
int f(void);
int gAll = 12;
int main(void){
//__func__ 可以打印出当前函数的函数名,下划线一边是两个
printf("in %s gAll = %d\n", __func__, gAll);
//全局变量可以直接使用,不需要再声明
f();
printf("again in %s gAll = %d\n", __func__, gAll);
//函数内对全局变量值的改变在 main函数中依然存在
return 0;
}
int f(void) {
printf("in %s gAll = %d\n", __func__, gAll);
gAll += 2;
printf("again in %s gAll = %d\n", __func__, gAll);
return gAll;
}
```
输出:
```c
in main gAll = 12
in f gAll = 12
again in f gAll = 14
again in main gAll = 14
```
###### 全局变量的初始化
- 没有初始化的全局变量**默认值为 0**
- 指针默认为 **NULL**
- 只能用**编译时刻已知**[^1]的值来初始化全局变量
- 全局变量的初始化发生在main函数之前
注释1:
```c
int gAll = 12;
int g = gAll;//报错
int main(void) {
return 0;
}
```
下面这段代码在某些编译器(dev c++)上是可以编译的,但是在 vs 上是不能编译的
```c
const int gAll = 12;
int g = gAll;
int main(void) {
return 0;
}
```
**但是,这种方式是不推荐的**
###### 被隐藏的全局变量
- 如果函数内部存在与全局变量同名的变量,则全局变量被隐藏。
```c
int f(void);
int gAll = 12;
int main(void) {
printf("in %s gAll = %d\n", __func__, gAll);
f();
printf("again in %s gAll = %d\n", __func__, gAll);
return 0;
}
int f(void) {
int gAll = 2;//仅在这个范围内适用
printf("in %s gAll = %d\n", __func__, gAll);
gAll += 2;
printf("again in %s gAll = %d\n", __func__, gAll);
return gAll;
}
```
输出:
```c
in main gAll = 12
in f gAll = 2
again in f gAll = 4
again in main gAll = 12
```
即使 gAll 在 main 函数中被覆盖,f 函数中的 gAll 也是不会被该改变的
为什么会这样?自己思考一下。
#### 静态本地变量
- 在本地变量定义时加上 static 修饰符就成为静态本地变量
- 当离开函数的生存期后,静态本地变量会继续存在并保持其值
- 静态本地变量的初始化只会在第一次进入这个函数时进行,以后进入函数时会保持上次离开时的值。
例:
**不用static**的情况
```c
int f(void);
int main(void) {
f();
f();
f();
return 0;
}
int f(void) {
int All = 1;
printf("in %s All = %d\n", __func__, All);
All += 2;
printf("again in %s All = %d\n", __func__, All);
return All;
}
```
输出:
```c
in f All = 1
again in f All = 3
in f All = 1
again in f All = 3
in f All = 1
again in f All = 3
```
**使用static**:
```c
int f(void);
int main(void) {
f();
f();
f();
return 0;
}
int f(void) {
static int All = 1;//只添加 static
printf("in %s All = %d\n", __func__, All);
All += 2;
printf("again in %s All = %d\n", __func__, All);
return All;
}
```
输出:
```c
in f All = 1
again in f All = 3
in f All = 3
again in f All = 5
in f All = 5
again in f All = 7
```
**看看地址**
```c
int f(void);
int gAll = 12;
int main(void) {
printf("1 st\n");
f();
printf("2 nd\n");
f();
return 0;
}
int f(void) {
int a = 0;
int b = 0;
static int All = 1;
printf("&All : %p\n", &All);
printf("&gAll: %p\n", &gAll);
printf("&a : %p\n", &a);
printf("&b : %p\n", &b);
return All;
}
```
输出:
```c
1 st
&All : 00007FF6A9ECC054
&gAll: 00007FF6A9ECC050
&a : 000000E8815CF8B4
&b : 000000E8815CF8D4
2 nd
&All : 00007FF6A9ECC054
&gAll: 00007FF6A9ECC050
&a : 000000E8815CF8B4
&b : 000000E8815CF8D4
```
全局变量 gAll 与 静态局部变量 All 在内存中相邻
**总结**
- 静态本地变量实际上是特殊的全局变量
- 它们位于相同的内存区域
- 静态本地变量具有全局的生存期,函数内的局部作用域
#### 返回指针的函数
请同学们先看一下下面这个程序:
```c
int* f(void);
void g(void);
int main(void) {
int* p = f();
printf("*p = %d\n", *p);
g();
printf("*p = %d\n", *p);
return 0;
}
int* f(void) {
int i = 12;
return &i;
}
void g(void) {
int k = 24;
printf("k = %d\n", k);
return k;
}
```
输出:
```c
*p = 12
k = 24
*p = 24
```
**i 和 k 的内存其实是同一块空间**
**总结**
- 返回 **本地变量** 的地址是危险的
- 返回 **全局变量** 或 **静态局部变量** 的地址是安全的
- 返回函数内 malloc 的内存是安全的,但是容易造成问题
- 最好的做法是**返回传入的指针**
说了这么多,总结一句话
###### 尽量避免使用 全局变量 和 静态本地变量
???
1.创建一个 c文件
2.写一个简单的带宏的 c程序
3.这时后我们成功创建了一个 c文件
4.编译c文件,并保留中间文件
文件详细情况
我们看看 .i 文件的 结尾部分
对比 .c 文件
替换字符串
FRORMAT 同样被替换了
编译器给了 warning
FORMAT并没有被替换
注意运算顺序