《编写高质量代码:改善c程序代码的125个建议》——建议8-3:不要混淆static变量的作用

简介:

本节书摘来自华章计算机《编写高质量代码:改善c程序代码的125个建议》一书中的第1章,建议8-3,作者:马 伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

建议8-3:不要混淆static变量的作用

在C语言中,static关键字不仅可以用来修饰变量,还可以用来修饰函数。在使用static关键字修饰变量时,我们称此变量为静态变量。静态变量的存储方式与全局变量一样,都是静态存储方式。但这里需要特别说明的是,静态变量属于静态存储方式,属于静态存储方式的变量却不一定就是静态变量。例如,全局变量虽然属于静态存储方式,但并不是静态变量,它必须由 static加以定义后才能成为静态全局变量。
考虑到可能会有不少读者对静态变量作用不太清楚,本节就来详细讨论一下它的主要
作用。
1.隐藏与隔离的作用
上面已经阐述过,全局变量虽然属于静态存储方式,但并不是静态变量。全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,全局变量在各个源文件中都是有效的,比如上面代码清单1-26-main中的全局变量g_X与g_Y就是如此。
如果我们希望全局变量仅限于在本源文件中使用,在其他源文件中不能引用,也就是说限制其作用域只在定义该变量的源文件内有效,而在同一源程序的其他源文件中不能使用。这时,就可以通过在全局变量之前加上关键字static来实现,即使全局变量被定义成为一个静态全局变量。下面将代码清单1-26-main中的全局变量g_X与g_Y全部修改为静态全局变量,代码如下所示:

#include <stdio.h>
/*定义两个静态全局变量*/
static int g_X=10;     
static int g_Y=20;
int max();     
int main(void)
{
    int result;
    result = max();
    printf("the max value is %d\n",result);
    return 0;
}

这时候,我们再来编译该程序,代码清单1-26-max将无法调用代码清单1-26-main中的静态全局变量g_X与g_Y。也就是说静态全局变量g_X与g_Y只能在代码清单1-26-main中使用,如图1-41所示。


<a href=https://yqfile.alicdn.com/686624dd6aee0bfa4099ee5d117ef1828e4e4d4a.png" >

在图1-41中,虽然g_X与g_Y变量仍然是全局的,但由于静态全局变量的作用域局限于一个源文件内,所以只能为该源文件内的函数所共用,这样就可以避免在其他源文件中引起的错误。也就起到了对其他源文件进行隐藏与隔离错误的作用,有利于模块化程序设计。
2.保持变量内容的持久性
有时候,我们希望函数中局部变量的值在函数调用结束之后不会消失,而仍然保留其原值。即它所占用的存储单元不释放,在下一次调用该函数时,其局部变量的值仍然存在,也就是上一次函数调用结束时的值。这时候,我们就应该将该局部变量用关键字static声明为“静态局部变量”。
当将局部变量声明为静态局部变量的时候,也就改变了局部变量的存储位置,即从原来的栈中存放改为静态存储区存放。这让它看起来很像全局变量,其实静态局部变量与全局变量的主要区别就在于可见性,静态局部变量只在其被声明的代码块中是可见的。
对某些必须在调用之间保持局部变量的值的子程序而言,静态局部变量是特别重要的。如果没有静态局部变量,则必须在这类函数中使用全局变量,由此也就打开了引入副作用的大门。使用静态局部变量最好的示例就是实现统计次数的功能,如代码清单1-27所示。

代码清单1-27 静态局部变量使用示例
#include <stdio.h>
void count();
int main(void)
{
    int i=0;
    for (i = 0; i <= 5; i++)
    {
            count();
    }
    return 0;
}
void count()
{
    /*声明一个静态局部变量*/
    static num = 0;
    num++;
    printf("%d\n",num);
}

在代码清单1-27中,我们通过在count()函数里声明一个静态局部变量num来作为计数器。因为静态局部变量是在编译时赋初值的,且只赋初值一次,在程序运行时它已有初值。以后在每次调用函数时就不再重新赋初值,而是保留上次函数调用结束时的值。这样,count()函数每次被调用的时候,静态局部变量num就会保持上一次调用的值,然后再执行自增运算,这样就实现了计数功能。同时,它又避免了使用全局变量。
通过上面的示例,我们可以得出静态局部变量一般的使用场景,如下所示:
需要保留函数上一次调用结束时的值。
如果初始化后,变量只会被引用而不会改变其值,则这时用静态局部变量比较方便,以免每次调用时重新赋值。
3.默认初始化为0
在静态数据区,内存中所有的字节默认值都是0x00。静态变量与全局变量也一样,它们都存储在静态数据区中,因此其变量的值默认也为0。演示示例如代码清单1-28
所示。

代码清单1-28 默认为0的演示示例
#include <stdio.h>
static int g_x;
int g_y;
int main(void)
{
    static int x;
    printf("g_x:%d\ng_y:%d\nx:%d",g_x,g_y,x);
    return 0;
}

代码清单1-28的运行结果如图1-42所示。


4a75d76f2ba553a0dc045a36ef5157d69b58bed8
相关文章