Loading... ### 变量 与 函数 #### 变量 ##### 局部变量 > 作用域:在定义变量的 `{}` 之内有效 > > 生命周期:程序运行至 **变量定义处开辟空间**【以底层角度解释,这个说法不是绝对的,源码中只要定义了变量,然后经过编译器的编译后,二进制指令已经是存在固定的,所以当执行到函数开辟内存的指令,**不管是否会执行定义变量的语句,,开辟多大空间的值是已经计算固定的**】,所在的函数结束之后释放空间 ```c #include<stdio.h> int main() { //int a = 11; int* p = (int*)0x12345678; if (0) { int b = 2; printf("%d\n", &b); } printf("%d\n", &b); // error,在定义变量的 大括号 之内才可以有效访问 } ``` > 在定义变量的 大括号 之内有效:在 `if大括号之内定义`,**只在** `if大括号之内有效`  ##### 静态局部变量 > 作用域:在定义变量的 `{}` 之内有效 > > 存储在 `静态区`【可读可写】 > > 只初始化一次,之后的函数调用不会再进行初始化 > > 初始化时,没有进行重新赋值,那么默认值就是 `0` > > 生命周期:`main函数执行前开辟空间`,**整个程序运行结束后释放空间** ```c #include<stdio.h> int main() { { static int num; } // printf("%d\n", num); // // error,在定义变量的 大括号 之内才可以有效访问 } ```  ###### 分析静态局部变量的生命周期 > 程序在编译阶段就为 `static` 修饰的变量 分配好空间。默认值是`0`,`static`修饰的变量在 `静态区`, > > 该静态区 **可读可写** 。 > > `只初始化一次`,之后的函数调用不会再进行初始化 > > 初始化时,没有进行重新赋值,那么默认值就是 `0` > > 所以以下程序中的初始化 `static`,可以忽略重复的定义 ``` #include<stdio.h> void fun() { static int num = 1; num++; printf("%d\n", num); } int main() { fun(); fun(); } ``` ```x86asm fun: 00401010 push ebp 00401011 mov ebp,esp 00401013 sub esp,40h 00401016 push ebx 00401017 push esi 00401018 push edi 00401019 lea edi,[ebp-40h] 0040101C mov ecx,10h 00401021 mov eax,0CCCCCCCCh 00401026 rep stos dword ptr [edi] 00401028 mov eax,[num (00424d8c)] 0040102D add eax,1 00401030 mov [num (00424d8c)],eax 00401035 mov ecx,dword ptr [num (00424d8c)] 0040103B push ecx 0040103C push offset string "%d\n" (0042201c) 00401041 call printf (00401070) 00401046 add esp,8 00401049 pop edi 0040104A pop esi 0040104B pop ebx 0040104C add esp,40h 0040104F cmp ebp,esp 00401051 call __chkesp (004010f0) 00401056 mov esp,ebp 00401058 pop ebp 00401059 ret main: 0040D700 push ebp 0040D701 mov ebp,esp 0040D703 sub esp,40h 0040D706 push ebx 0040D707 push esi 0040D708 push edi 0040D709 lea edi,[ebp-40h] 0040D70C mov ecx,10h 0040D711 mov eax,0CCCCCCCCh 0040D716 rep stos dword ptr [edi] 0040D718 call @ILT+5(_fun) (00401010) 0040D71D call @ILT+5(_fun) (00401010) 0040D722 pop edi 0040D723 pop esi 0040D724 pop ebx 0040D725 add esp,40h 0040D728 cmp ebp,esp 0040D72A call __chkesp (004010f0) 0040D72F mov esp,ebp 0040D731 pop ebp 0040D732 ret ``` > 从 `0040D718`处 调用fun函数,然在fun函数中发现并没有重新给 `static` 修饰的`num`变量赋值。推断出,程序在编译阶段就为 `static` 修饰的变量 分配好空间。默认值是`0`,`static`修饰的变量在 `静态区`。 ##### 全局变量 > 作用于 `整个工程`,所有文件都可用,**在其他文件中使用该变量的时候提前声明即可** > > 存储在 `静态区`【可读可写】 > > 生命周期:程序运行 到 程序运行结束 `demo.c` ```c #include<stdio.h> int num = 0x123; // 定义全局部变量,作用域范围:所有的源文件都可访问,前提是使用时候声明即可 void fun1() { } ``` `main.c` ``` #include<stdio.h> extern int num; int main() { printf("%X\n", num); } ``` > 在 `main.c` 使用 其他文件定义的全局变量 `num`, > 那么就在使用前声明 `extern 要使用的变量的变量类型 要使用的变量;` -> `extern int num;` ##### 静态全局变量 > 作用于 `当前文件`,只适用于单个文件, > > 存储在 `静态区`【可读可写】 > > 生命周期:程序运行 到 程序运行结束 `main.c` ``` #include<stdio.h> static int num; int main() { printf("%X\n", num); } ``` #### 函数 ##### 静态函数 > 定义函数时,使用 `static` 修饰的函数 > > 作用域:**只允许当前文件直接调用** ,其他文件想调用该函数,那么可以通过 **间接方式** 调用函数 ```c #include <stdio.h> #include <string.h> #include <stdlib.h> static int function() { return 0; } ``` ##### 全局函数 > 定义函数时,未使用 `static` 修饰的函数 > > 作用域:**只允许所有`.c`文件 调用函数** > 例如:`main` 函数 ### 总结 > 1. 局部变量:`普通局部变量`、`静态局部变量` > > - 普通局部变量 > > 作用域范围:**定义的位置** 在 **最近的大括号之内** 才是有效访问 > > 变量存储在`栈中`,默认值是 `随机值` > > 生命周期:**函数开始到函数结束** > - 静态局部变量 > > 作用域范围:**定义的位置** 在 **最近的大括号之内** 才是有效访问 > > 变量存储在 `静态区` ,默认值是`0` > > 生命周期:**程序开始到程序结束** > 2. 全局变量:`普通全局变量`、`静态全局变量` > > - 普通全局变量 > > 作用域范围:**作用在所有源文件** > > 变量存储在`静态区`,默认值是`0` > > 生命周期:**程序开始到程序结束** > - 静态全局变量 > > 作用域范围:**作用在当前定义的源文件** > > 变量存储在`静态区`,默认值是`0` > > 生命周期:**程序开始到程序结束** <div class="tip inlineBlock error"> > 在 `.h` 文件中,全局变量只声明不定义,定义只放在 `.c` 文件 </div> 最后修改:2022 年 04 月 10 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏