C语言static关键字详解(代码+原理+图解)
目录
static 关键字的原理
总结
补充
static 关键字作用
1. 隐藏:当我们同时编译多个文件时,所有未加 static 前缀的全局变量和函数都具有全局可见性;加上后就不再具有全局可见性。
//extern.c 源文件
char c = 'A'; //全局变量
void func()//全局函数
{
printf("You can see me\n");
}
//main.c 源文件
int main( )
{
extern char c;//外部变量在使用前必须声明
printf("%c\n", c);
func();//使用外部函数,可以不声明
return 0;
}
可以看到在一个多文件编写的程序里,通过 extern 是可以访问全局函数和全局变量的。
注意:前提是加上 extern 关键字声明一下,函数可以不加,变量不加不行,否则存在二义性,因为编译器不知道 char c 是未初始化变量的定义,还是一个变量的声明。为了严谨性都带上最好。
//extern.c 源文件
static char c = 'A'; //静态全局变量
static void func()//静态全局函数
{
printf("You can see me\n");
}
可以看到,加上 static 关键字修饰后,主函数里面再调用就会报链接错误,编译器不认识这俩货。
为什么在 extern.c 中定义的全局变量 c 和函数 func能 在main.c 中使用?这是因为所有未加static 前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。
此例中,c 是全局变量,func 是全局函数,并且都没有加 static 前缀,因此对于另外的源文件 main.c 是可见的,如果加了static,就会对其它源文件隐藏,例如在 c 和 func 的定义前加上static,main.c就看不到它们了。
利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。static 可以用作函数和变量的前缀,对于函数来讲,static 的作用仅限于隐藏。
本质其实是将全局变量和全局函数的外部链接属性转换成了内部链接属性,extern 失效了。
2. 持久化:保持变量内容持久化
全局变量和静态变量都是存储在静态区的,存储在静态数据区的变量会在程序刚开始运行时就完成定义和初始化,也是唯一的一次定义和初始化。
共有两种变量存储在静态存储区:全局变量和 static 变量,只不过和全局变量比起来,static 可以控制变量的可见范围,说到底 static 还是用来隐藏的。
//普通的局部变量
void test()
{
int a = 3;
a++;
printf("%d ", a);
}
int main()
{
int i = 0;
while (i < 10)//循环10次
{
test();
i++;
}
return 0;
}
普通的局部变量出了 test 函数的作用域就会被销毁,数据是暂时的。
//静态局部变量
void test()
{
static int a = 3;//静态局部变量
a++;
printf("%d ", a);
}
int main()
{
int i = 0;
while (i < 10)//循环10次
{
test();
i++;
}
return 0;
}
而 static 修饰后的变量 a 出了 test 的作用域后并没有被销毁,还是继续存在的,是内容得到了持久化。
3. 默认初始化置 0
其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。
在静态数据区,内存中所有的字节默认值都是 0x00,某些时候这一特点可以减少程序员的工作量,比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置 0,然后把不是 0 的几个元素赋值,如果定义成静态的,就省去了一开始置 0 的操作,再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加’\0’太麻烦,如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是 '\0'。
int a;//全局变量
int main(void)
{
static char str[10];//静态变量
printf("a=%d\n", a);
printf("str=xx%sxx\n", str);
return 0;
}
可以看到,全局变量和静态变量没有初始化,但是打印的值都是默认为0
注意:‘\0’ 本质就是 0,打印的时候由于第一个就是 \0,所以不打印任何字符,所以xx和xx之间没有内容。
static 关键字的原理
普通的数据是放在内存的栈区上,会受到自己作用域的限制,进入作用域生效,出了作用域失效。
当被 static 修饰的时候,数据则是在静态区存储的的,这时存储的数据,出了作用域变量不会销毁,得到了持久化。
本质实际是改变了存储位置:栈区--->静态区,使得数据的生命周期发生了变化。
借助例子解释,未被 static 修饰的时候, a 是一个局部变量,进入test 函数后,a 被创建,生命周期开始,出了 test 函数后,生命周期结束,a 被销毁,每次进入都会创建a=3,然后变成 4
而 static 修饰局部变量a后,F11进入 test 函数后再按F10,会跳过里面的ststic int a = 3 这行代码,这就意味着局部静态变量的重复定义和初始化只在最开始的时候执行一次,之后就不再执行,并且查看 a 的地址始终没有变,说明每次进去用的都是同一个 a,所以 a 会累加。
注意:静态变量也是变量,只要不是常量,都是可以被修改的。
总结
- static 全局变量与普通的全局变量有什么区别 ?
① 全局变量(外部变量)的声明之前再冠以 static 就构成了静态的全局变量,全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式,所以这两者在存储方式上并无不同
② 这两者的区别在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的,而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它,由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误
- static 局部变量和普通局部变量有什么区别 ?
① 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期,而把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围
② static 全局变量只定义并初使化一次,防止在其他文件单元中被引用
- static 函数与普通函数有什么区别?
① static 函数与普通函数作用域不同,仅在本文件有效,只在当前源文件中使用的函数应该声明为内部函数(static 修饰的函数),内部函数应该在当前源文件中说明和定义,对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
② static 函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
补充
链接属性:
1.外部连接属性---------通过链接的方式跨源文件访问------全局变量、全局函数
2.内部链接属性-------static 修饰后
3.无链接属性-------局部变量
注意:
1.外部链接属性是跨源文件相互访问
2.加了static只能在本文件下使用,名字不会冲突(因为别的文件看不到,不知道这个名字)
CSDN-Ada助手: 恭喜您发布了第四篇博客!不干净的VMware卸载确实是一个让人头疼的问题,您的经验分享对于遇到类似情况的读者们一定会帮助很大。希望您能继续保持创作的热情和分享精神,也许下一步可以尝试深入研究一些高级技巧或者解决方案,让您的博客内容更加丰富多彩。期待您的下一篇作品! 如何快速涨粉,请看该博主的分享:https://hope-wisdom.blog.csdn.net/article/details/130544967?utm_source=csdn_ai_ada_blog_reply5
小C您好: 太棒了,又有新知识
CSDN-Ada助手: 恭喜您写下了第三篇博客!标题看起来非常吸引人,对于学习C语言的读者来说,这篇博客一定非常有价值。通过代码、原理和图解的结合,读者可以更加深入地理解C语言中的static关键字。您的努力和付出确实让人印象深刻。 在下一步的创作中,我谦虚地建议您可以考虑扩展主题,例如探讨其他关键字或概念的用法和原理。这样可以为读者提供更全面的知识体系。当然,这只是一个建议,您可以根据自己的兴趣和经验来决定下一篇博客的主题。再次恭喜您,期待您更多精彩的创作! CSDN 正在通过评论红包奖励优秀博客,请看红包流:https://bbs.csdn.net/?type=4&header=0&utm_source=csdn_ai_ada_blog_reply3
CSDN-Ada助手: 这是一篇非常实用的博文!你的快捷键汇总对于使用Visual Studio的开发人员来说肯定非常有帮助。坚持写作,分享你的经验和技巧,对于其他开发人员也是一种巨大的帮助。 除了常见的快捷键之外,还有一些与Visual Studio相关的扩展知识和技能。例如,你可以探索Visual Studio的调试功能,学习如何设置断点、观察变量和使用调试窗口。另外,了解如何使用代码片段和代码生成器可以进一步提高你的开发效率。此外,熟悉Visual Studio的插件和扩展生态系统,可以帮助你发现更多的工具和功能,以满足你的开发需求。 希望你能继续分享你的经验和学习心得,期待看到更多关于Visual Studio的实用技巧和优化建议!谢谢你的分享! 如何写出更高质量的博客,请看该博主的分享:https://blog.csdn.net/lmy_520/article/details/128686434?utm_source=csdn_ai_ada_blog_reply2