变量 与 函数

变量

局部变量

作用域:在定义变量的 {} 之内有效

生命周期:程序运行至 变量定义处开辟空间【以底层角度解释,这个说法不是绝对的,源码中只要定义了变量,然后经过编译器的编译后,二进制指令已经是存在固定的,所以当执行到函数开辟内存的指令,不管是否会执行定义变量的语句,,开辟多大空间的值是已经计算固定的】,所在的函数结束之后释放空间

#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函数执行前开辟空间整个程序运行结束后释放空间

#include<stdio.h>
int main() {
    {
        static int num;
    }
    // printf("%d\n", num); 
    // 
    // error,在定义变量的 大括号 之内才可以有效访问
}

分析静态局部变量的生命周期

程序在编译阶段就为 static 修饰的变量 分配好空间。默认值是0static修饰的变量在 静态区

该静态区 可读可写

只初始化一次,之后的函数调用不会再进行初始化

初始化时,没有进行重新赋值,那么默认值就是 0

所以以下程序中的初始化 static,可以忽略重复的定义

#include<stdio.h>
void fun() {
    static int num = 1;
    num++;
    printf("%d\n", num);
}

int main() {
    fun();
    fun();
}
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 修饰的变量 分配好空间。默认值是0static修饰的变量在 静态区
全局变量

作用于 整个工程,所有文件都可用,在其他文件中使用该变量的时候提前声明即可

存储在 静态区【可读可写】

生命周期:程序运行 到 程序运行结束

demo.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 修饰的函数

作用域:只允许当前文件直接调用 ,其他文件想调用该函数,那么可以通过 间接方式 调用函数

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static int function()
{
    return 0;

}
全局函数

定义函数时,未使用 static 修饰的函数

作用域:只允许所有.c文件 调用函数
例如:main 函数

总结

  1. 局部变量:普通局部变量静态局部变量

    • 普通局部变量

      作用域范围:定义的位置最近的大括号之内 才是有效访问

      变量存储在栈中,默认值是 随机值

      生命周期:函数开始到函数结束

    • 静态局部变量

      作用域范围:定义的位置最近的大括号之内 才是有效访问

      变量存储在 静态区 ,默认值是0

      生命周期:程序开始到程序结束

  2. 全局变量:普通全局变量静态全局变量

    • 普通全局变量

      作用域范围:作用在所有源文件

      变量存储在静态区,默认值是0

      生命周期:程序开始到程序结束

    • 静态全局变量

      作用域范围:作用在当前定义的源文件

      变量存储在静态区,默认值是0

      生命周期:程序开始到程序结束

.h 文件中,全局变量只声明不定义,定义只放在 .c 文件

最后修改:2022 年 04 月 10 日
如果觉得我的文章对你有用,请随意赞赏