zoukankan      html  css  js  c++  java
  • extern和static使用

    1. 声明和定义

    ​  当定义一个变量的时候,就包含了对该变量声明的过程,同时在内存张申请了一块内存空间。如果在多个文件中使用相同的变量,为了避免重复定义,就必须将声明和定义分离开来。定义是创建与名字关联的实体。声明是让名字为程序所知,当一个文件想要使用其他文件定义的某个变量,则必须包含对那个文件的声明:

    1. 函数和变量的声明不会分配内存, 但是定义会分配相应的内存空间

    2. 函数和变量的声明可以有很多次, 但是定义最多只能有一次

    3. 函数的声明和定义方式默认都是 extern 的, 即函数默认是全局的

    4. 变量的声明和定义方式默认都是局部的, 在当前编译单元或者文件内可用

      了解声明和定义对static和extern的理解有辅助作用。比如extern就是在一处定义,其他文件都只需要声明即可,不可重复定义。

    2. static& extern

    2.1 static

      一般局部变量是存储在栈区的,局部变量的生命周期在其所在的语句块执行结束时便结束了。但如果用static修饰局部变量,那么这个变量就不会存储在栈区而是放在静态数据区,其生命周期会一直持续到整个程序结束,该变量只在初次运行时进行初始化,且只进行一次,但是它的作用域只能是在函数里面如下:

    void print(){
         static int z = 100;
         z++;
         cout << z <<endl;
    }
    ​
    int main(){
        print();
        print();
        print();
        return 0;
    }

    局部静态变量z只能在本文件的print函数里面访问,一旦超出作用域范围,就无法访问。

      如果是static修饰的全局变量,且实现的函数写在头文件(h)中,在其他文件也可以访问,如下:

    //  a.h 
    #ifndef A_H
    #define A_H
    #include<iostream>
    using namespace std;
    static char str[] = "hello";
    namespace sextern {
    void print1();
    void Fun1();
    void Fun1(){
        str[0] = 'l';
    }
    void print1(){
          cout << "value  " << str <<endl;
          cout << "address  " << &str <<endl;
    }
    }
    #endif // A_H
    ​
    ​
    //b.h
    #ifndef B_H
    #define B_H
    namespace sextern{
    void Fun2(){
        str[0] = 'o';
    }
    void print2(){
        cout << "value  " << str <<endl;
        cout << "address  " << &str <<endl;
    }
    #endif // B_H
    ​
    //main.cpp
    #include "a.h"
    #include "b.h"
    using namespace sextern;
    int main(int argc, char *argv[])
    {
        sextern::Fun1();
        print1();
        sextern::Fun2();
        print2();
        print1();
        return 0;
    }
    ​
    //结果如下
    /*
     *  value  lello
     *  address  0x601058
     *  value  oello
     *  address  0x601058
     *  value  oello
     *  address  0x601058
     *  按 <RETURN> 来关闭窗口...
     */

    发现将static全局变量写在头文件中,所有文件的头文件的操作都会共享这个变量。

      但如果是在源文件(cpp)中去操作这个静态全局变量,则这个静态全局变量只能在当前文件有效,但是在另外一个文件访问此静态变量,会是该变量初始的默认值,不会是其他文件中修改的值,虽然它们有相同的初始内容,但是存储的物理地址并不一样。如下:

    //a.h
    #ifndef A_H
    #define A_H
    #include<iostream>
    using namespace std;
    static char str[] = "hello";
    namespace sextern {
    void Fun1();
    void print1();
    }
    #endif // A_H
    ​
    //a.cpp
    #include "a.h"
    namespace sextern {
    void Fun1(){
        str[0] = 'l';
    }
    void print1(){
          cout << "value  " << str << endl;
          cout << "address  " << &str <<endl;
    }
    }
    ​
    //c.h
    #ifndef C_H
    #define C_H
    #include<iostream>
    using  namespace std;
    namespace sextern {
    void Fun3();
    void print3();
    }
    #endif // C_H
    ​
    //c.cpp
    #include "c.h"
    #include "a.h"
    namespace sextern {
    void Fun3(){
        str[0] = 'o';
    }
    void print3(){
        cout << "value  " << str <<endl;
        cout << "address  " << &str <<endl;
    }
    }
    ​
    ​
    #include "a.h"
    #include "c.h"
    using namespace sextern;
    int main(int argc, char *argv[])
    {
        sextern::Fun1();
        print1();
        sextern::Fun3();
        print3();
        print1();
        return 0;
    }
    ​
    //结果如下
    /*
     *  value  lello
     *  address  0x602064
     *  value  oello
     *  address  0x60205e
     *  value  lello
     *  address  0x602064
     *  按 <RETURN> 来关闭窗口...
     */

    在a.h的头文件中定义了一个静态的全局变量x,不同文件的函数fun1和fun3会为每个包含该头文件的cpp都创建一个全局变量,但他们都是独立的,只在该cpp文件共享该变量。所以一般定义static全局变量时,都把它放在原文件中而不是头文件,从而避免多个源文件共享,就不会给其他模块造成不必要的信息污染。如果想要在不同文件共享同一个全局变量,这个时候就要用到extern。

    2.2 extern

      当在某个文件定义了一个全局变量,如果要在另一个文件去使用该变量,如果再次去定义,则会出现重复定义的问题,这个时候就需要使用到声明,对该变量的声明告诉编译器该变量在其他文件中已经定义,在此处要去引用它。上述的代码改成如下形式:

    //b.h
    #ifndef B_H
    #define B_H
    char str[] = "hello";   //定义一个全局变量
    #endif // B_H
    ​
    //a.h
    #ifndef A_H
    #define A_H
    #include<iostream>
    using namespace std;
    extern char str[];
    namespace sextern {
    void Fun1();
    void print1();
    }
    #endif // A_H
    ​
    //a.cpp
    #include "a.h"
    namespace sextern {
    void Fun1(){
        str[0] = 'l';
    }
    void print1(){
          cout << "value  " << str << endl;
          cout << "address  " << &str <<endl;
    }
    }
    ​
    //c.h
    #ifndef C_H
    #define C_H
    #include<iostream>
    using  namespace std;
    extern char str[];
    namespace sextern {
    void Fun3();
    void print3();
    }
    #endif // C_H
    ​
    //c.cpp
    #include "c.h"
    namespace sextern {
    void Fun3(){
        str[0] = 'o';
    }
    void print3(){
        cout << "value  " << str <<endl;
        cout << "address  " << &str <<endl;
    }
    }
    ​
    //结果如下
    /*
     *  value  lello
     *  address  0x602058
     *  value  oello
     *  address  0x602058
     *  value  oello
     *  address  0x602058
     *  按 <RETURN> 来关闭窗口...
     */

    参考资料

    详解C/C++中的static和extern

    C/C++中extern关键字详解

     

     

     

  • 相关阅读:
    Java8新特性之lambda表达式
    查询数据库存在特殊列字段的所有表的表名和字段名
    BigDecimal相关整理
    MyBatis正在爬的坑
    Java面试题整理
    qs库的使用
    配置proxy解决跨域问题
    PDF.js 使用方式
    HTML转义以及防止JS注入攻击
    jquery ajax跨域回调
  • 原文地址:https://www.cnblogs.com/helloworldcode/p/11191231.html
Copyright © 2011-2022 走看看