static修饰局部变量
图一:test 函数里面定义的 a 是局部变量,局部变量在栈区上开辟空间,栈区的使用特点是进入变量的生命周期时自动为其开辟空间,离开变量的生命周期时自动销毁对应空间,所以这里每次调用 test 函数时 a 都会被重新定义并初始化为0,所以屏幕上打印的是10个1;
图二:我们把 a 用 static 修饰后发现屏幕打印的是1到10,就好像每次调用完 test 函数后 a 并没有被销毁,而是继续使用,下次调用 test 函数时 a 直接在之前的基础上进行 ++ 操作。
所以 static 修饰局部变量的作用是:改变局部变量的生命周期,本质上是改变了局部变量的存储位置,让局部变量不再是在栈区上开辟空间,而是直接在静态区上开辟空间,从而使得局部变量拥有和全局变量一样的生命周期,即随着整个程序生成和销毁。
更深入的理解 static 修饰局部变量的作用:图三,我们的程序从源文件(.c文件)变成可执行程序(.exe文件)需要经过编译链接运行三个环节,而编译环节又分为预处理、编译、汇编三个阶段,在汇编阶段,编译器会把我们的C语言代码转换成汇编代码,而每一条C语言语句都对应着多句汇编代码,然而在图三中,我们可以观察到,只有 static int a = 0; 这条语句没有对应的汇编代码,也就是说,C语言在编译的时候会直接跳过这条语句。
本质上是:在编译环节的编译阶段编译器就会为被 static 修饰的局部变量分配空间,所以C程序在运行的过程中会直接跳过 static 修饰的语句,也就是说,在第二次及以上甚至第一次调用 test 函数时 static int a = 0; 这条语句都不会被执行。
static 修饰全局变量
图一图二对比分析:我在Add.c中定义了一个全局变量g_val,因为全局变量具有外部链接属性,所以我只需要在test.c中对g_val进行声明之后就可以正常使用了,但是当我用 static 来修饰g_val时,我们发现,编译器说g_val是无法解析的外部符号;
所以 static 修饰全局变量的作用是:改变了全局变量的外部链接属性(可以在其他源文件内被访问),使其变成内部连接属性(只能在本文件内部被访问),给我们的感觉是全局变量的作用域变小了。
static 修饰函数
图一图二对比分析:这里和 static 修饰全局变量非常类似,我在Add.c中定义了一个Add函数,因为函数也具有外部链接属性,所以我只需要在test.c中对Add函数进行声明之后就可以正常使用了,但是当我用 static 来修饰Add函数时,我们发现,编译器说Add是无法解析的外部符号;
所以 static 修饰函数的作用是:改变了函数的外部链接属性(可以在其他源文件内被访问),使其变成内部连接属性(只能在本文件内部被访问),给我们的感觉是函数的作用域变小了。
总结
static 修饰局部变量的作用:改变局部变量的生命周期,本质上是改变了局部变量的存储位置,让局部变量不再是在栈区上开辟空间,而是直接在静态区上开辟空间,从而使得局部变量拥有和全局变量一样的生命周期,即随着整个程序生成和销毁。
static 修饰全局变量的作用:改变了全局变量的外部链接属性(可以在其他源文件内被访问),使其变成内部连接属性(只能在本文件内部被访问)。
static 修饰函数的作用是:改变了函数的外部链接属性(可以在其他源文件内被访问),使其变成内部连接属性(只能在本文件内部被访问)。