鱼C论坛

 找回密码
 立即注册
查看: 17795|回复: 44

[扩展阅读] 第002讲:【*】使用 static 的三个理由

[复制链接]
发表于 2014-5-11 13:38:26 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
转自:http://www.cnblogs.com/dc10101/archive/2007/08/22/865556.html

在 C 语言中,static 的字面意思很容易把我们导入歧途,其实它的作用有三条。



(1)先来介绍它的第一条也是最重要的一条:隐藏

当我们同时编译多个文件时,所有未加 static 前缀的全局变量和函数都具有全局可见性。为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是 a.c,另一个是 main.c。

下面是 a.c 的内容
char a = 'A'; // global variable
void msg() 
{
    printf("Hello\n"); 
}
下面是main.c的内容
int main(void)
{    
    extern char a;    // extern variable must be declared before use
    printf("%c ", a);
    (void)msg();

    return 0;      
}
程序的运行结果是:

A Hello

你可能会问:为什么在 a.c 中定义的全局变量 a 和函数 msg 能在 main.c 中使用?前面说过,所有未加 static 前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。此例中,a 是全局变量,msg 是函数,并且都没有加 static 前缀,因此对于另外的源文件 main.c 是可见的。

如果加了 static,就会对其它源文件隐藏。例如在 a 和 msg 的定义前加上 static,main.c 就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。static 可以用作函数和变量的前缀,对于函数来讲,static 的作用仅限于隐藏,而对于变量,static 还有下面两个作用。


(2)static 的第二个作用是保持变量内容的持久

存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。

共有两种变量存储在静态存储区:全局变量和 static 变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。虽然这种用法不常见,但我还是举一个例子。
#include <stdio.h>

int fun(void)
{
    static int count = 10;    // 事实上此赋值语句从来没有执行过
    return count--;
}

int count = 1;

int main(void)
{    
    printf("global\t\tlocal static\n");
    for(; count <= 10; ++count)
        printf("%d\t\t%d\n", count, fun());    
    
    return 0;
}
程序的运行结果是:

global      local static

1               10

2               9

3               8

4               7

5               6

6               5

7               4

8               3

9               2

10             1


(3)static 的第三个作用是默认初始化为 0

其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是 0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置 0,然后把不是 0 的几个元素赋值。如果定义成静态的,就省去了一开始置 0 的操作。

再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加 '\0' 太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是 '\0'。不妨做个小实验验证一下。
#include <stdio.h>

int a;

int main(void)
{
    int i;
    static char str[10];

    printf("integer: %d;  string: (begin)%s(end)", a, str);

    return 0;
}
程序的运行结果是:

integer: 0; string: (begin)(end)

最后对 static 的三条作用做一句话总结。首先 static 的最主要功能是隐藏,其次因为 static 变量存放在静态存储区,所以它具备持久性和默认值 0。


评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
贾政景 + 5 + 5 + 3

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2014-5-11 14:37:12 | 显示全部楼层
学习了,多谢楼主分享!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-5-11 17:11:19 | 显示全部楼层
static 隐藏 没有看明白
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-5-11 17:13:10 | 显示全部楼层
具体隐藏了什么?

点评

如果加了 static,就会对其它源文件隐藏。例如在 a 和 msg 的定义前加上 static,main.c 就看不到它们了。  详情 回复 发表于 2014-5-11 21:33
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-5-11 21:33:24 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-5-11 22:54:01 | 显示全部楼层
大赞甲鱼。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-5-12 18:52:17 | 显示全部楼层
小甲鱼 发表于 2014-5-11 21:33
如果加了 static,就会对其它源文件隐藏。例如在 a 和 msg 的定义前加上 static,main.c 就看不到它们了。 ...

非常感谢 甲鱼哥 我明白了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-5-13 11:34:48 | 显示全部楼层
#include <stdio.h>
int a;
int main(void)
{        
            int i;        
                 char str[5]={'A','B','C'};
              // static char str[5]={'A','B','C'};        
                   printf("integer: %d;  string: (begin)%s(end)", a, str);        
                  return 0;        
        }
甲鱼老师! 你看这个加不加static都一样啊! 都能正确输出ABC。感觉字符数组应该是没有显示初始化字符,那后面几个数组元素自动补0的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-5-13 11:43:26 | 显示全部楼层
  static int count = 10;    // 事实上此赋值语句从来没有执行过

这句话什么意思?在初次运行的时候进行过一次初始化吧,后续的调用就不再初始化了吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 2 反对 0

使用道具 举报

发表于 2014-5-17 07:01:02 | 显示全部楼层
非常感谢 甲鱼哥 我明白了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-5-21 13:19:19 | 显示全部楼层
数组初始化。。你没学好  char str[5]={'A','B','C'};
默认其它元素初始化零
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-6-1 22:16:56 | 显示全部楼层
真是长见识了,谢谢小甲鱼!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-6-6 22:06:51 | 显示全部楼层
一直记到static的前两个作用,却忘了最后的初始化为0的作用了,就当复习一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-6-9 18:41:27 | 显示全部楼层
今天又涨姿势了:lol:
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-6-19 20:31:15 | 显示全部楼层
应该是只执行了一次,从未执行就不对了吧。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-6-22 13:41:51 | 显示全部楼层
总结看完就明白了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-7-20 19:01:52 | 显示全部楼层

隐藏了之后,你在main函数中   加上了extern的外部申明也不能调用它  ,明白了嘛?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2014-7-20 19:05:49 | 显示全部楼层
E=MC2 发表于 2014-5-13 11:34
甲鱼老师! 你看这个加不加static都一样啊! 都能正确输出ABC。感觉字符数组应该是没有显示初始化字符,那 ...

这个不一样,你在定义静态字符数组时候已经给他初始化了!!
而且字符数组输出的结束标志就是   判断最后一个元素是否为0   当str【3】 = 0  时就出来啦!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-7-20 21:38:51 | 显示全部楼层
赵得伟 发表于 2014-7-20 19:05
这个不一样,你在定义静态字符数组时候已经给他初始化了!!
而且字符数组输出的结束标志就是   判断最 ...

你的意思是
#include <stdio.h>
int a;
int main(void)
{              
        char str[5];//没有初始化
    //static char str[5]; //已经初始化      
        printf("integer: %d;  string: (begin)%s(end)", a, str);  
        return 0;        
 }
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2014-10-1 14:49:47 | 显示全部楼层
了解。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-21 22:46

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表