从static关键字说起

来源:互联网 发布:七天网络阅卷app 编辑:程序博客网 时间:2024/05/20 06:50

为什么linux的驱动方法都加static关键字呢?带着这个疑问,我有了下边的一些收获。

ok,从最基本的static关键字在c语言中的作用说起吧。

在c语言中static关键字用来描述变量和函数有不用的作用,先来看函数:

我写了两个文件main.c和b.c:

//b.c中定义了一个static修饰的方法   static void staticTest(){        printf("static test is running...");      }//main.c中调用   void main(){         staticTest();     }

       这种情况下调用会出错,原因就是用static关键字修饰的函数只在本文件内有效(文件作用域)。 可以说这个staticTest函数属于b.c这个文件。

       当然用static来修饰一个全局变量也是相同的结果,但是如果用static修饰一个局部变量会有什么结果?我在main.c中定义了两个方法:

void main(){        run();    run();    run2();    run2();    }static void run(){      int x = 2;     x++;      printf("x is %d\n",x);     }void run2(){     static x = 2;     x++;     printf("x is %d\n",x);     }


运行结果:

x is 3;x is 3;x is 3;x is 4;


也就是说,static修饰的局部变量不管函数被调用多少次,这个局部变量只有一份。
为什么会这样,这个得分析一下内存模型。这是linux进程的内存模型:

 


先了解几个概念:
栈:从高地址向低地址扩展

堆:从低地址向高地址扩展(因为你不知道堆和栈具体的空间大小,这样类似双端队列的做法可以充分利用空间)
(忽然想到以前从数据库中取出的数据作为数组存在heap中导致内存溢出,以前以为是stack溢出,现在明白是heap溢出)

bss segment:未初始化段,看图识字。

data segment:初始化段,看图识字。

Text segment:也叫code segment,放些只读的数据,我理解常量也放这里。(一直搞不懂常量区到哪??)

 

好的,开始:起初,当程序以二进制的形式被加载到内存中,stack中什么也没有,bss中被清零,data中初始化全局变量,text中存放一些只读(rodata)的常量。
当有函数被调用的时候,就会生成一个栈帧(stack frame):

栈帧:一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里等等。

将栈帧插入到栈中,例如运行同一个函数两次就会有两个栈帧被插入,栈帧中的非静态局部变量的值是从常量区中取得,就是说,每个栈帧都有属于它的一份局部变量,但是:静态局部变量的值只有一份,所有栈帧共用一个值。
我说的有点乱,看个例子(来自网上):

//main.cpp  int a = 0; 全局初始化区  char *p1; 全局未初始化区  main()  {  int b; //栈  char s[] = "abc"; //栈  char *p2; //栈  char *p3 = "123456"; //123456\0在常量区,p3在栈上。  static int c =0; //全局(静态)初始化区  p1 = (char *)malloc(10);  p2 = (char *)malloc(20);  //分配得来得10和20字节的区域就在堆区。  strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。  }  


可以看到静态变量的值不存在常量区。常量区放的是只读的数据(供栈帧从中复制值,复制后值不变),静态变量及其值都是存储在bss和data段,可以在程序运行时修改的(栈帧不复制,直接使用)。

写到这里我又想起一个困扰我很久的问题(原谅我是个Java程序员):

 

                String str = new String("abc");//存放在堆中                   String str = "abc";//先在栈中创建一个String类的对象指针str,然后查找文字中有没有存放"abc",如果没有,则将"abc"存放进文字常量区,并令str指向"abc",如果已经有"abc"则直接令str指向"abc" 


ok,关于static关键字在c语言中的作用就讲到这里,关于static关键字在c++中的用法(c++中有class来划定边界,因此static有public、private之分),有时间再写。
               
 回归起初的问题,为什么linux驱动函数都要交static关键字,为了不让用户调用, 我们知道linux有系统空间和用户空间,而驱动就是工作再系统空间,和内核是同一级别, 内核大部分都是驱动,而linux内核也只有一个main函数(起初操作系统只有一个init进程,其他进程由它生成),也就是说加上static之后,内核可以调用,而用户不可以调用。

 

这里有个问题:static关键字修饰函数只在文件内有效,我的理解就是b.c中有效,那么为什么linux 内核函数可以调用呢?? 

原创粉丝点击