google了近三页的关于C语言中static的内容,发现可用的信息非常少,要么长篇大论不知所云要么在关键之处几个字略过,对于想挖掘底层原理的刚開始学习的人来说參考性不是非常大。所以,我这篇博文博採众家之长,把互联网上的资料整合归类,并亲手编敲代码验证之。

C语言代码是以文件为单位来组织的,在一个源程序的全部源文件里,一个外部变量(注意不是局部变量)或者函数仅仅能在一个源程序中定义一次,假设有反复定义的话编译器就会报错。伴随着不同源文件变量和函数之间的相互引用以及相互独立的关系,产生了extern和statickeyword。

以下,具体分析一下statickeyword在编敲代码时有的三大类使用方法:

一,static全局变量

我们知道,一个进程在内存中的布局如图1所看到的:

当中.text段保存进程所运行的程序二进制文件,.data段保存进程全部的已初始化的全局变量,.bss段保存进程未初始化的全局变量(其它段中还有非常多乱七八糟的段,暂且不表)。在进程的整个生命周期中,.data段和.bss段内的数据时跟整个进程同生共死的,也就是在进程结束之后这些数据才会寿终就寝。

当一个进程的全局变量被声明为static之后,它的中文名叫静态全局变量。静态全局变量和其它的全局变量的存储地点并没有差别,都是在.data段(已初始化)或者.bss段(未初始化)内,可是它仅仅在定义它的源文件内有效,其它源文件无法訪问它。所以,普通全局变量穿上static外衣后,它就变成了新娘,已心有所属,仅仅能被定义它的源文件(新郎)中的变量或函数訪问。

下面是一些演示样例程序

file1.h例如以下:

#include <stdio.h>

void printStr();

我们在file1.c中定义一个静态全局变量hello, 供file1.c中的函数printStr訪问.

#include "file1.h"

static char* hello = "hello cobing!";

void printStr()
{
printf("%s\n", hello);
}

file2.c是我们的主程序所在文件,file2.c中假设引用hello会编译出错

#include "file1.h"

int main()
{
printStr();
printf("%s\n", hello);
return 0;
}

报错例如以下:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

file2.c: In function ‘main’:

file2.c:6: 错误:‘hello’ 未声明 (在此函数内第一次使用)

file2.c:6: 错误:(即使在一个函数内多次出现,每一个未声明的标识符在其

file2.c:6: 错误:所在的函数内仅仅报告一次。)



假设我们将file2.c改为以下的形式:

#include "file1.h"

int main()
{
printStr();
return 0;
}

则会顺利编译连接。

执行程序后的结果例如以下:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

[liujx@server235 static]$ ./file2

hello cobing!



上面的样例中,file1.c中的hello就是一个静态全局变量,它能够被同一文件里的printStr调用,可是不能被不同源文件里的file2.c调用。

二,static局部变量

普通的局部变量在栈空间上分配,这个局部变量所在的函数被多次调用时,每次调用这个局部变量在栈上的位置都不一定同样。局部变量也能够在堆上动态分配,可是记得使用完这个堆空间后要释放之。

static局部变量中文名叫静态局部变量。它与普通的局部变量比起来有例如以下几个差别:

1)位置:静态局部变量被编译器放在全局存储区.data(注意:不在.bss段内,原因见3)),所以它尽管是局部的,可是在程序的整个生命周期中存在。

2)訪问权限:静态局部变量仅仅能被其作用域内的变量或函数訪问。也就是说尽管它会在程序的整个生命周期中存在,因为它是static的,它不能被其它的函数和源文件訪问。

3)值:静态局部变量假设没有被用户初始化,则会被编译器自己主动赋值为0,以后每次调用静态局部变量的时候都用上次调用后的值。这个比較好理解,每次函数调用静态局部变量的时候都改动它然后离开,下次读的时候从全局存储区读出的静态局部变量就是上次改动后的值。

下面是一些演示样例程序:

file1.h的内容和上例中的同样,file1.c的内容例如以下:

#include "file1.h"

void printStr()
{
int normal = 0;
static int stat = 0; //this is a static local var
printf("normal = %d ---- stat = %d\n",normal, stat);
normal++;
stat++;
}

为了便于比較,我定义了两个变量:普通局部变量normal和静态局部变量stat,它们都被赋予初值0;

file2.c中调用file1.h:

#include "file1.h"

int main()
{
printStr();
printStr();
printStr();
printStr();
printf("call stat in main: %d\n",stat);
return 0;
}

这个调用会报错,由于file2.c中引用了file1.c中的静态局部变量stat,例如以下:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

file2.c: In function ‘main’:

file2.c:9: 错误:‘stat’ 未声明 (在此函数内第一次使用)

file2.c:9: 错误:(即使在一个函数内多次出现,每一个未声明的标识符在其

file2.c:9: 错误:所在的函数内仅仅报告一次。)

编译器说stat未声明,这是由于它看不到file1.c中的stat,以下注掉这一行:

#include "file1.h"

int main()
{
printStr();
printStr();
printStr();
printStr();
// printf("call stat in main: %d\n",stat);
return 0;
}

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

[liujx@server235 static]$ ./file2

normal = 0 ---- stat = 0

normal = 0 ---- stat = 1

normal = 0 ---- stat = 2

normal = 0 ---- stat = 3

执行如上所看到的。能够看出,函数每次被调用,普通局部变量都是又一次分配,而静态局部变量保持上次调用的值不变。

须要注意的是因为static局部变量的这样的特性,使得含静态局部变量的函数变得不可重入,即每次调用可能会产生不同的结果。这在多线程编程时可能会成为一种隐患。须要多加注意。

三,static函数

              相信大家还记得C++面向对象编程中的private函数,私有函数仅仅有该类的成员变量或成员函数能够訪问。在C语言中,也有“private函数”,它就是接下来要说的static函数,完毕面向对象编程中private函数的功能。

当你的程序中有非常多个源文件的时候,你肯定会让某个源文件仅仅提供一些外界须要的接口,其它的函数可能是为了实现这些接口而编写,这些其它的函数你可能并不希望被外界(非本源文件)所看到,这时候就能够用static修饰这些“其它的函数”。

所以static函数的作用域是本源文件,把它想象为面向对象中的private函数就能够了。

以下是一些演示样例:

file1.h例如以下:

#include <stdio.h>

static int called();
void printStr();

file1.c例如以下:

#include "file1.h"

static int called()
{
return 6;
}
void printStr()
{
int returnVal;
returnVal = called();
printf("returnVal=%d\n",returnVal);
}

file2.c中调用file1.h中声明的两个函数,此处我们有益调用called():

#include "file1.h"

int main()
{
int val;
val = called();
printStr();
return 0;
}

编译时会报错:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

file1.h:3: 警告:‘called’ 使用过但从没有定义

/tmp/ccyLuBZU.o: In function `main':

file2.c:(.text+0x12): undefined reference to `called'

collect2: ld 返回 1

由于引用了file1.h中的static函数,所以file2.c中提示找不到这个函数:undefined reference to 'called'

以下改动file2.c:

#include "file1.h"

int main()
{
printStr();
return 0;
}

编译执行:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

[liujx@server235 static]$ ./file2

returnVal=6

static函数能够非常好地解决不同原文件里函数同名的问题,由于一个源文件对于其它源文件里的static函数是不可见的。



有疏漏的地方望各位多多不吝赐教~~

C语言中的static 具体分析的更多相关文章

  1. C语言中的static 详细分析

    转自:http://blog.csdn.net/keyeagle/article/details/6708077/ google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇大 ...

  2. 【转载】C语言中的static 详细分析

    原blog地址:http://blog.csdn.net/keyeagle/article/details/6708077/ google了近三页的关于C语言中static的内容,发现可用的信息很少, ...

  3. 转:C语言中的static变量和C++静态数据成员(static member)

    转自:C语言中的static变量和C++静态数据成员(static member) C语言中static的变量:1).static局部变量        a.静态局部变量在函数内定义,生存期为整个程序 ...

  4. C语言中的static的作用?

    在C语言中,static的字面意思很容易把我们导入歧途,其实它的作用有三条. (1)第一个作用:隐藏. 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性.为理解这句话 ...

  5. C语言中的static关键字

    C语言代码是以文件为单位来组织的,在一个源程序的所有源文件中,一个外部变量(注意不是局部变量)或者函数只能在一个源程序中定义一次,如果有重复定义的话编译器就会报错.伴随着不同源文件变量和函数之间的相互 ...

  6. C语言中的static和extern

    c语言中,全局变量是一个非常重要的概念.全局变量定义在函数外,可以被所有的函数共同使用. #include <iostream> ; void display() { printf(&qu ...

  7. C语言中:static与extern对变量和函数的作用

    1.两者对全局变量 static对全局变量,表示定义一个内部变量 extern对全局变量,表示声明一个外部变量 说明: 1.内部变量:定义的变量只能在本文件中访问,不能被其他文件访问. 2.不同文件中 ...

  8. [整理]C语言中的static静态对象

    1.说明外部对象(静态外部变量和静态函数)    (1)static 用于说明外部变量或函数,使该对象的作用域限定为被编译原文件的剩余部分,即从对象说明开始到所在源文件的结束部分:    (2)被st ...

  9. C语言中,static关键字作用

    static修饰变量 1 在块中使用static修饰变量 它具有静态存储持续时间.块范围和无链接. 即作用域只能在块中,无法被块外的程序调用:变量在程序加载时创建,在程序终止时结束. 它只在编译时初始 ...

随机推荐

  1. POJ2421 & HDU1102 Constructing Roads(最小生成树)

    嘎唔!~又一次POJ过了HDU错了...不禁让我想起前两天的的Is it a tree?   orz..这次竟然错在HDU一定要是多组数据输入输出!(无力吐槽TT)..题目很简单,炒鸡水! 题意: 告 ...

  2. vc2008构建和使用libcurl静态库

    1>下载CURL源代码curl-7.26.0.zip 2>用VC2008/2005打开工程curl-7.26.0\lib\libcurl.vcproj,转换下工程并构建,可以直接编译成功! ...

  3. cx_Oracle模块学习之绑定变量

    有些时候我们需要和程序交互,此时需要绑定量下面两个例子简介在SELECT 和 DML 里面绑定变量的用法 SELECT 里面的绑定变量 [root@Ora10G py]# cat SelectBind ...

  4. QTableView 固定列宽度(鼠标拖动后,仍可固定)

    QTableView 提供一个函数: void QTableView::setColumnWidth ( int column, int width ) 用于设置column指定的列的宽度 但setC ...

  5. hdu4496 D-City

    D-City Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Total Submis ...

  6. 使用ROW_NUMBER()查询:列名 'RowNumber' 无效。

    原文:使用ROW_NUMBER()查询:列名 'RowNumber' 无效. 使用ROW_NUMBER()方法查询结果集:语句如下:   select ROW_NUMBER() OVER(ORDER ...

  7. SaaS怎样改变了商务世界

    当下,全球的经济环境愈发复杂,竞争日益激烈,这就要求企业负责人高速适应和调整战略应对挑战.假设你的企业可以优化内部操作流程,走在新技术的前沿,你就行减少成本.改善服务质量.没有及时应对的企业非常快就会 ...

  8. ios 6 横竖屏转换

    xcode 版本4.5     模拟器:6.0 项目需求:刚进去界面横屏,从这个界面进去的界面全是竖屏. 程序的根控制器用了UINavigationController.下面是代码: 1.在appde ...

  9. MVC应用程序与单选列表

    原文:MVC应用程序与单选列表 前几天,Insus.NET有在MVC应用程序中,练习了<MVC应用程序,动态创建单选列表(RadioButtonList)>http://www.cnblo ...

  10. Window8.1 64位无法使用Debug命令的解决方法[附牛人代码]

    偶然看到网上一篇文章,讲的是世界黑客编程大赛第一名的一个很酷的程序,大小仅有4KB,使用debug命令执行. 悲催的是win8.1的debug命令不能使用. 错误例如以下: 解决方法例如以下: 1. ...