zoukankan      html  css  js  c++  java
  • static 和extern关键字

    static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性。extern "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。本文主要介绍C/C++中的static和extern关键字。

     

    static是C++中常用的修饰符,它被用来控制变量的存贮方式和可见性。extern, "C"是使C++能够调用C写作的库文件的一个手段,如果要对编译器提示使用C的方式来处理函数的话,那么就要使用extern "C"来说明。

    一.C语言中的static关键字

    在C语言中,static可以用来修饰局部变量,全局变量以及函数。在不同的情况下static的作用不尽相同。

    (1)修饰局部变量

    一般情况下,对于局部变量是存放在栈区的,并且局部变量的生命周期在该语句块执行结束时便结束了。但是如果用static进行修饰的话,该变量便存放在静态数据区,其生命周期一直持续到整个程序执行结束。但是在这里要注意的是,虽然用static对局部变量进行修饰过后,其生命周期以及存储空间发生了变化,但是其作用域并没有改变,其仍然是一个局部变量,作用域仅限于该语句块。

    在用static修饰局部变量后,该变量只在初次运行时进行初始化工作,且只进行一次。

    如:

    1. #include<stdio.h>  
    2. void fun()  
    3. {   
    4. static int a=1; a++;   
    5. printf("%d ",a);  
    6. }  
    7. int main(void)  
    8. {   
    9. fun();   
    10. fun();   
    11. return 0;  
    12. }  

    程序执行结果为: 2  3

    说明在第二次调用fun()函数时,a的值为2,并且没有进行初始化赋值,直接进行自增运算,所以得到的结果为3.

    对于静态局部变量如果没有进行初始化的话,对于整形变量系统会自动对其赋值为0,对于字符数组,会自动赋值为''.

    (2)修饰全局变量

    对于一个全局变量,它既可以在本源文件中被访问到,也可以在同一个工程的其它源文件中被访问(只需用extern进行声明即可)。

    如:

    1. //有file1.c  
    2. int a=1;  
    3. file2.c  
    4. #include<stdio.h>  
    5. extern int a;  
    6. int main(void)  
    7. {  
    8. printf("%d",a);  
    9. return 0;  

    则执行结果为 1

    但是如果在file1.c中把int a=1改为static int a=1;

    那么在file2.c是无法访问到变量a的。原因在于用static对全局变量进行修饰改变了其作用域的范围,由原来的整个工程可见变为本源文件可见。

    总结:

    static变量,不管是局部还是全局,都存放在静态存储区。

    表面意思就是不auto,变量在程序初始化时被分配,直到程序退出前才被释放;也就是static是按照程序的生命周期来分配释放变量的,而不是变量自己的生命周期如果在main前设置断点,然后查看static变量,已经被初始化,也就是说static在执行main函数前已经被初始化。也就是在程序初始化时被分配。

    (3)修饰函数

    用static修饰函数的话,情况与修饰全局变量大同小异,就是改变了函数的作用域。

    头文件中的static变量

    如果在一个头文件中声明:

           static int g_vaule = 0;

          那么会为每个包含该头文件的c都创建一个全局变量,但他们都是独立的;所以也不建议这样的写法,一样不明确需要怎样使用这个变量,因为只是创建了一组同名而不同作用域的变量。

    二.C++中的static

    在C++中static还具有其它功能,如果在C++中对类中的某个函数用static进行修饰,则表示该函数属于一个类而不是属于此类的任何特定对象;如果对类中的某个变量进行static修饰,表示该变量为类以及其所有的对象所有。它们在存储空间中都只存在一个副本。可以通过类和对象去调用。

    三.extern关键字

    在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。
    在上面的例子中可以看出,在file2中如果想调用file1中的变量a,只须用extern进行声明即可调用a,这就是extern的作用。在这里要注意extern声明的位置对其作用域也有关系,如果是在main函数中进行声明的,则只能在main函数中调用,在其它函数中不能调用。其实要调用其它文件中的函数和变量,只需把该文件用#include包含进来即可,为啥要用extern?因为用extern会加速程序的编译过程,这样能节省时间。

    在C++中extern还有另外一种作用,用于指示C或者C++函数的调用规范。比如在C++中调用C库函数,就需要在C++程序中用extern “C”声明要引用的函数。这是给链接器用的,告诉链接器在链接的时候用C函数规范来链接。主要原因是C++和C程序编译完成后在目标代码中命名规则不同,用此来解决名字匹配的问题。

    extern对变量和函数的用法:

    extern

    (1)变量

    尤其是对于变量来说。
    extern int a;//声明一个全局变量a
    int a; //定义一个全局变量a

    extern int a =0 ;//定义一个全局变量a 并给初值。
    int a =0;//定义一个全局变量a,并给初值,

    第四个 等于 第 三个,都是定义一个可以被外部使用的全局变量,并给初值。
    糊涂了吧,他们看上去可真像。但是定义只能出现在一处。也就是说,不管是int a;还是extern int a=0;还是int a=0;都只能出现一次,而那个extern int a可以出现很多次。

    当你要引用一个全局变量的时候,你就要声明,extern int a;这时候extern不能省略,因为省略了,就变成int a;这是一个定义,不是声明。

    (2)函数
         函数,函数,对于函数也一样,也是定义和声明,定义的时候用extern,说明这个函数是可以被外部引用的,声明的时候用extern说明这是一个声明。 但由于函数的定义和声明是有区别的,定义函数要有函数体,声明函数没有函数体,所以函数定义和声明时都可以将extern省略掉,反正其他文件也是知道这个函数是在其他地方定义的,所以不加extern也行。两者如此不同,所以省略了extern也不会有问题。
        比如:
    /*某cpp文件*/
    int fun(void)
    {
    return 0;
    }

    很好,我们定义了一个全局函数
    /*另一cpp文件*/
    int fun(void);
    我们对它做了个声明,然后后面就可以用了
    加不加extern都一样
    我们也可以把对fun的声明 放在一个头文件里,最后变成这样
    /*fun.h*/
    int fun(void);//函数声明,所以省略了extern,完整些是extern int fun(void);
    /*对应的fun.cpp文件*/
    int fun(void)
    {
    return 0;
    }//一个完整的全局函数定义,因为有函数体,extern同样被省略了。
    然后,一个客户,一个要使用你的fun的客户,把这个头文件包含进去,ok,一个全局的声明。没有问题。
    但是,对应的,如果是这个客户要使用全局变量,那么要extern 某某变量;不然就成了定义了。

    总结下:

    对变量而言,如果你想在本源文件中使用另一个源文件的变量,就需要在使用前用extern声明该变量,或者在头文件中用extern声明该变量;

    对函数而言,如果你想在本源文件中使用另一个源文件的函数,就需要在使用前用声明该变量,声明函数加不加extern都没关系,所以在头文件中函数可以不用加extern。

    对变量而言:定义的时候可以省掉关键字extern,但声明的时候不可以省。

    对函数而言:定义的时候可以省掉关键字extern,声明的时候同样可以省。

    函数名字代表函数的入口地址,所以函数和变量本质上是一样的,对于用extern声明的变量(函数)会首先在本文件中查找,查找不到的情况下会在其他模块查找.

    转载:

    http://developer.51cto.com/art/201104/256820.htm

    http://xpwu627.blog.163.com/blog/static/2367729520091183326822/

  • 相关阅读:
    ubuntu 制做samba
    《Programming WPF》翻译 第4章 前言
    《Programming WPF》翻译 第4章 3.绑定到数据列表
    《Programming WPF》翻译 第4章 4.数据源
    《Programming WPF》翻译 第5章 6.触发器
    《Programming WPF》翻译 第4章 2.数据绑定
    《Programming WPF》翻译 第4章 1.不使用数据绑定
    《Programming WPF》翻译 第5章 7.控件模板
    《Programming WPF》翻译 第5章 8.我们进行到哪里了?
    《Programming WPF》翻译 第5章 5.数据模板和样式
  • 原文地址:https://www.cnblogs.com/3me-linux/p/3848103.html
Copyright © 2011-2022 走看看