精华内容
下载资源
问答
  • 静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。该变量在全局数据区内分配内存;静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行...
  • 如果定义成局部变量,则必须定义成静态局部变量静态局部变量是在编译时赋初值的,只赋初值一次,以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。
  • 本文主要讲了static静态局部变量的使用技巧,希望对你的学习有所帮助。
  • 1、局部变量能否和全局变量重名?  答:能,局部会屏蔽全局。要用全局变量,需要使用 ":: "  局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器...

    1、局部变量能否和全局变量重名?   

      答:能,局部会屏蔽全局。要用全局变量,需要使用 ":: " 

        局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。 

    2、如何引用一个已经定义过的全局变量?   

      答:可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。 


    3、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?  

      答:可以,在不同的C文件中以static形式来声明同名全局变量。前提是只能有一个C文件中对此变量赋初值,连接才不会出错 

     

    4、语句for( ;1 ;)有什么问题?它是什么意思?  

      答:和while(1)相同。 


    5、do……while和while……do有什么区别?   

      答:前一个循环一遍再判断,后一个判断以后再循环   

    6、请写出下列代码的输出内容   

    #include <stdio.h>     
    main()     
    {      
    int a,b,c,d;      
    a=10;   
    b=a++;    
    c=++a;    
    d=10*a++;   
    printf( "b,c,d:%d,%d,%d",b,c,d);   
    return 0;   
    } 

     

     答:10,12,120 


    7、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别? 

    答:static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;

           static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;

           static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

     

    (1)用static定义的全局变量,构成静态的全局变量,若是一个源程序由多个源文件组成,一般的全局变量在各个源文件中都是有效的,而用static修饰的全局变量只在定义该变量的源文件中是有效的,因此static限制了全局变量的作用范围。
    (2)普通局部变量在所在的函数每次调用的时候都会被重新分配存储空间,函数结束后,就会回收该存储空间。而用static修饰的局部变量不会,它的值始终保持着。
    (3)static函数与普通函数作用域不同,它仅作用于定义它的源文件中。

    (4)储存方式:程序的局部变量存在于(堆栈)中,全局变量存在于(静态区/全局区)中,动态申请(new)数据存在于(堆)中。

      

    8.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?


    c用宏定义,  #define S(a,b) a*b

    c++用inline  

    引入内联函数的目的是为了解决程序中函数调用的效率问题。内联函数是指用inline关键字修饰的函数。任何在类的说明部分定义的

    函数都会被自动的认为是内联函数。

    它与一般函数所不同之处只在于函数调用的处理。

    内联函数必须是和函数体声明在一起才有效。像这样的申明Inline Tablefunction(int I)是没有效果的,编译器只是把函数作为普通的函数声明,

    我们必须定义函数体。

    Inline tablefunction(int I) {return I*I};  这样我们才算定义了一个内联函数。我们可以把它作为一般的函数一样调用。

    但是执行速度确比一般函数的执行速度要快。

    (C#有无内联函数:C#就没有头文件,哪来的内联外联?要说内联,应该全都是内联,因为所有函数什么的都定义在一个文件里。存在内联函数,但要注意,在何处内联代码的决定完全由CLR做出,我们无法使用像C++中inline这样的关键字来控制那些方法是内联的。)

     

     

    全局变量、局部变量、静态全局变量、静态局部变量的区别

    C++变量根据定义的位置的不同的生命周期,具有不同的作用域,作用域可分为6种:全局作用域,局部作用域,语句作用域,类作用域,命名空间作用域和文件作用域。

    从作用域看:

    全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。

    静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

    局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。

    静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。

    从分配内存空间看:
    全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间

     

     

    全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

        1)、静态变量会被放在程序的静态数据存储区(数据段)(全局可见)中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
      2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。

    从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。应予以注意。

    Tips:
      A.若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
      B.若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
      C.设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题,因为他们都放在静态数据存储区,全局可见;
        D.如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数)
        E.函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。

    -----------------------------------------------------------------------------------------------------------

    static 全局变量:改变作用范围,不改变存储位置

    static 局部变量:改变存储位置,不改变作用范围

    静态函数 :在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

                    如果在一个源文件中定义的函数,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用,这种函数也称为内部函数。定义一个内部函数,只需在函数类型前再加一个“static”关键字即可。

     

     

    参考:

    https://www.cnblogs.com/burandanxin/archive/2009/10/16/1584735.html

    https://blog.csdn.net/Zhanganliu/article/details/79185251

    展开全文
  • 按存储区域分:全局变量、静态全局变量和静态局部变量都存放在内存的全局数据区,局部变量存放在内存的栈区 按作用域分:   1、全局变量在整个工程文件内都有效; 2、静态全局变量只在定义它的文件内有效; ...


    按存储区域分:全局变量、静态全局变量和静态局部变量都存放在内存的全局数据区,局部变量存放在内存的栈区

    按作用域分:

    1、全局变量在整个工程文件内都有效;

    2、 静态全局变量只在定义它的文件内有效;

    3、 静态局部变量只在定义它的函数内有效,且程序仅分配一次内存,函数返回后,该变量不会消失;局部变量在定义它的函数内有效,但是函数返回后失效。
    4、 全局变量 静态变量如果没有手工初始化,则由编译器初始化为0。局部变量的值不可知。

    5、 静态局部变量 全局变量共享全局数据区, 但静态局部变量只在定义它的函数中可见。静态局部变量与局部变量在存储位置上不同,使得其存在的时限也不同,导致对这两者操作 的运行结果也不同。

    #include <stdio.h>
     
    void func();//函数声明,主要是因为被调用的函数定义写在了main函数后面了
     
    int n = 1; //全局变量
     
    int  main(void)
    {
        static int a; // 静态局部变量,但静态局部变量只在定义它的函数中可见,并且只初始化一次
        int b = -10; // 局部变量
     
        printf("main:   a=%d,   b=%d,   n=%d\n",a,b,n);
     
        b += 4;
     
        func();
     
        printf("main:   a=%d,   b=%d,   n=%d\n",a,b,n);
        n += 10;
     
        func();
        printf("main:   a=%d,   b=%d,   n=%d\n",a,b,n);
     
    }
    void func()
    {
        static int a = 2; // 静态局部变量
        int b = 5; // 局部变量
        a += 2;
        n += 12;
        b += 5;
       printf("func:   a=%d,   b=%d,   n=%d\n",a,b,n);
    }
    

    在这里插入图片描述
    结果分析:

    首先明确main函数和func函数里面都有静态局部变量a和局部变量b,由于它们的固有性质,它们都只在定义它的函数里有效,所以它们互不干扰,所以只要在本函数里分析即可,而全局变量n,在main和func函数里都有效,所以分析它的值应该考虑n在这两个函数里的变化

    展开全文
  • 静态局部变量 存在全局区 不初始化内容为0 整个进程结束空间释放 只能在定义所在的复合语句中有效 静态全局变量 存在全局区 不初始化内容为0 整个进程结束空间释放 只能在当前源文件中使用 ...
    项目ValueValueValueValue
    普通局部变量存在栈区不初始化内容随机只在定义的复合语句中有效复合语句结束变量空间释放
    普通全局变量存在全局区不初始化内容为0整个进程结束空间释放能被当前源文件或其他源文件使用,其他源文件使用时要加extern
    静态局部变量存在全局区不初始化内容为0整个进程结束空间释放只能在定义所在的复合语句中有效
    静态全局变量存在全局区不初始化内容为0整个进程结束空间释放只能在当前源文件中使用
    展开全文
  • 静态局部变量和静态全程变量static。

    万次阅读 多人点赞 2019-01-01 13:28:04
    我们知道在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何...

    1. 什么是static?

    static 是 C/C++ 中很常用的修饰符,它被用来控制变量的存储方式和可见性。

    1.1 static 的引入

    我们知道在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义为全局的变量,但定义一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅只受此函数控制)。static 关键字则可以很好的解决这个问题。

    另外,在 C++ 中,需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见时,可将其定义为静态数据。

    static 存储类

    static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。

    static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。

    全局声明的一个 static 变量或方法可以被任何函数或方法调用,只要这些方法出现在跟 static 变量或方法同一个文件中。

    以下实例演示了 static 修饰全局变量和局部变量的应用:

    实例

    #include <stdio.h> /* 函数声明 */ 
    
    void func1(void); 
    static int count=10; /* 全局变量 - static 是默认的 */ 
    int main()
     {
     while (count--) 
    { 
    func1(); 
    } return 0; 
    } 
    void func1(void) 
    { /* 'thingy' 是 'func1' 的局部变量 - 只初始化一次 * 每次调用函数 'func1' 'thingy' 值不会被重置。 */
     static int thingy=5; 
    thingy++;
     printf(" thingy 为 %d , count 为 %d\n", thingy, count); 
    }

    实例中 count 作为全局变量可以在函数内使用,thingy 使用 static 修饰后,不会在每次调用时重置。

    可能您现在还无法理解这个实例,因为我已经使用了函数和全局变量,这两个概念目前为止还没进行讲解。即使您现在不能完全理解,也没有关系,后续的章节我们会详细讲解。当上面的代码被编译和执行时,它会产生下列结果:

     thingy 为 6 , count 为 9
     thingy 为 7 , count 为 8
     thingy 为 8 , count 为 7
     thingy 为 9 , count 为 6
     thingy 为 10 , count 为 5
     thingy 为 11 , count 为 4
     thingy 为 12 , count 为 3
     thingy 为 13 , count 为 2
     thingy 为 14 , count 为 1
     thingy 为 15 , count 为 0

    extern 存储类

    extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。

    当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。

    extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候,如下所示:

    第一个文件:main.c

    实例

    #include <stdio.h> int count ; extern void write_extern(); int main() { count = 5; write_extern(); }

     

     

     

    1.2 静态数据的存储

    全局(静态)存储区:分为 DATA 段和 BSS 段。DATA 段(全局初始化区)存放初始化的全局变量和静态变量;BSS 段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BBS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。

    在 C++ 中 static 的内部实现机制:静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。

    这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类的成员函数定义;三是应用程序的 main() 函数前的全局数据声明和定义处。

    静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明只声明一个类的"尺寸和规格",并不进行实际的内存分配,所以在类声明中写成定义是错误的。它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对其重复定义。

    static 被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。

    优势:可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后的相同的值,这样可以提高时间效率。


    2. 在 C/C++ 中static的作用

    2.1 总的来说

    • (1)在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
    • (2)static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。
    • (3)static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为 0。
    • (4)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。
    • (5)考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用 static)。

    2.2 静态变量与普通变量

    静态全局变量有以下特点:

    • (1)静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量;
    • (2)未经初始化的静态全局变量会被程序自动初始化为0(在函数体内声明的自动变量的值是随机的,除非它被显式初始化,而在函数体外被声明的自动变量也会被初始化为 0);
    • (3)静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的。

    优点:静态全局变量不能被其它文件所用;其它文件中可以定义相同名字的变量,不会发生冲突。

    (1)全局变量和全局静态变量的区别

    • 1)全局变量是不显式用 static 修饰的全局变量,全局变量默认是有外部链接性的,作用域是整个工程,在一个文件内定义的全局变量,在另一个文件中,通过 extern 全局变量名的声明,就可以使用全局变量。
    • 2)全局静态变量是显式用 static 修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用 extern 声明也不能使用。

    2.3 静态局部变量有以下特点:

    • (1)该变量在全局数据区分配内存;
    • (2)静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
    • (3)静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为 0;
    • (4)它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。

    一般程序把新产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。

    看下面的例子:

    实例

    //example: #include <stdio.h> #include <stdlib.h> int k1 = 1; int k2; static int k3 = 2; static int k4; int main() { static int m1 = 2, m2; int i = 1; char*p; char str[10] = "hello"; char*q = "hello"; p = (char *)malloc(100); free(p); printf("栈区-变量地址 i:%p\n", &i); printf("栈区-变量地址 p:%p\n", &p); printf("栈区-变量地址 str:%p\n", str); printf("栈区-变量地址 q:%p\n", &q); printf("堆区地址-动态申请:%p\n", p); printf("全局外部有初值 k1:%p\n", &k1); printf(" 外部无初值 k2:%p\n", &k2); printf("静态外部有初值 k3:%p\n", &k3); printf(" 外静无初值 k4:%p\n", &k4); printf(" 内静态有初值 m1:%p\n", &m1); printf(" 内静态无初值 m2:%p\n", &m2); printf(" 文字常量地址:%p, %s\n", q, q); printf(" 程序区地址:%p\n", &main); return 0; }

    输出结果如下:


    3. static 用法

    3.1 在 C++ 中

    static 关键字最基本的用法是:

    • 1、被 static 修饰的变量属于类变量,可以通过类名.变量名直接引用,而不需要 new 出一个类来
    • 2、被 static 修饰的方法属于类方法,可以通过类名.方法名直接引用,而不需要 new 出一个类来

    被 static 修饰的变量、被 static 修饰的方法统一属于类的静态资源,是类实例之间共享的,换言之,一处变、处处变。

    在 C++ 中,静态成员是属于整个类的而不是某个对象,静态成员变量只存储一份供所有对象共用。所以在所有对象中都可以共享它。使用静态成员变量实现多个对象之间的数据共享不会破坏隐藏的原则,保证了安全性还可以节省内存。

    静态成员的定义或声明要加个关键 static。静态成员可以通过双冒号来使用即 <类名>::<静态成员名>。

    3.2 静态类相关

    通过类名调用静态成员函数和非静态成员函数:

    class Point { public: void init() { } static void output() { } }; void main() { Point::init(); Point::output(); }

    报错:

    'Point::init' : illegal call of non-static member function

    结论 1:不能通过类名来调用类的非静态成员函数。

    通过类的对象调用静态成员函数和非静态成员函数。

    class Point { public: void init() { } static void output() { } }; void main() { Point pt; pt.init(); pt.output(); }

    编译通过。

    结论 2:类的对象可以使用静态成员函数和非静态成员函数。

    在类的静态成员函数中使用类的非静态成员。

    #include <stdio.h> class Point { public: void init() { } static void output() { printf("%d\n", m_x); } private: int m_x; }; void main() { Point pt; pt.output(); }

    编译出错:

    error C2597: illegal reference to data member 'Point::m_x' in a static member function

    因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样。

    结论3:静态成员函数中不能引用非静态成员。

    在类的非静态成员函数中使用类的静态成员。

    class Point { public: void init() { output(); } static void output() { } }; void main() { Point pt; Pt.init(); pt.output(); }

    编译通过。

    结论 4:类的非静态成员函数可以调用用静态成员函数,但反之不能。

    使用类的静态成员变量。

    #include <stdio.h> class Point { public: Point() { m_nPointCount++; } ~Point() { m_nPointCount--; } static void output() { printf("%d\n", m_nPointCount); } private: static int m_nPointCount; }; void main() { Point pt; pt.output(); }

    按 Ctrl+F7 编译无错误,按 F7 生成 EXE 程序时报链接错误。

    error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA)

    这是因为类的静态成员变量在使用前必须先初始化。

    在 main() 函数前加上 int Point::m_nPointCount = 0; 再编译链接无错误,运行程序将输出 1。

    结论 5:类的静态成员变量必须先初始化再使用。

    思考总结:静态资源属于类,但是是独立于类存在的。从 J 类的加载机制的角度讲,静态资源是类初始化的时候加载的,而非静态资源是类实例化对象的时候加载的。 类的初始化早于类实例化对象,比如 Class.forName("xxx") 方法,就是初始化了一个类,但是并没有实例化对象,只是加载这个类的静态资源罢 了。所以对于静态资源来说,它是不可能知道一个类中有哪些非静态资源的;但是对于非静态资源来说就不一样了,由于它是实例化对象出来之后产生的,因此属于类的这些东西它都能认识。所以上面的几个问题答案就很明确了:

    • 1)静态方法能不能引用非静态资源?不能,实例化对象的时候才会产生的东西,对于初始化后就存在的静态资源来说,根本不认识它。
    • 2)静态方法里面能不能引用静态资源?可以,因为都是类初始化的时候加载的,大家相互都认识。
    • 3)非静态方法里面能不能引用静态资源?可以,非静态方法就是实例方法,那是实例化对象之后才产生的,那么属于类的内容它都认识。

    static 修饰类:这个用得相对比前面的用法少多了,static 一般情况下来说是不可以修饰类的, 如果 static 要修饰一个类,说明这个类是一个静态内部类(注意 static 只能修饰一个内部类),也就是匿名内部类。像线程池 ThreadPoolExecutor 中的四种拒绝机制 CallerRunsPolicy、AbortPolicy、DiscardPolicy、 DiscardOldestPolicy 就是静态内部类。静态内部类相关内容会在写内部类的时候专门讲到。)

    3.3 总结:

    • (1)静态成员函数中不能调用非静态成员。
    • (2)非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。
    • (3)静态成员变量使用前必须先初始化(如 int MyClass::m_nNumber = 0;),否则会在 linker 时出错。

    一般总结:在类中,static 可以用来修饰静态数据成员和静态成员方法。

    静态数据成员

    • (1)静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。
    • (2)静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。
    • (3)静态数据成员可以被初始化,但是只能在类体外进行初始化,若未对静态数据成员赋初值,则编译器会自动为其初始化为 0。
    • (4)静态数据成员既可以通过对象名引用,也可以通过类名引用。

    静态成员函数

    • (1)静态成员函数和静态数据成员一样,他们都属于类的静态成员,而不是对象成员。
    • (2)非静态成员函数有 this 指针,而静态成员函数没有 this 指针。
    • (3)静态成员函数主要用来方位静态数据成员而不能访问非静态成员。

    再给一个利用类的静态成员变量和函数的例子以加深理解,这个例子建立一个学生类,每个学生类的对象将组成一个双向链表,用一个静态成员变量记录这个双向链表的表头,一个静态成员函数输出这个双向链表。

    实例

    #include <stdio.h> #include <string.h> const int MAX_NAME_SIZE = 30; class Student { public: Student(char *pszName); ~Student(); public: static void PrintfAllStudents(); private: char m_name[MAX_NAME_SIZE]; Student *next; Student *prev; static Student *m_head; }; Student::Student(char *pszName) { strcpy(this->m_name, pszName); //建立双向链表,新数据从链表头部插入。 this->next = m_head; this->prev = NULL; if (m_head != NULL) m_head->prev = this; m_head = this; } Student::~Student ()//析构过程就是节点的脱离过程 { if (this == m_head) //该节点就是头节点。 { m_head = this->next; } else { this->prev->next = this->next; this->next->prev = this->prev; } } void Student::PrintfAllStudents() { for (Student *p = m_head; p != NULL; p = p->next) printf("%s\n", p->m_name); } Student* Student::m_head = NULL; void main() { Student studentA("AAA"); Student studentB("BBB"); Student studentC("CCC"); Student studentD("DDD"); Student student("MoreWindows"); Student::PrintfAllStudents(); }

    程序将输出:

     

    static变量称为静态变量。根据变量的类型可以分为静态局部变量和静态全程变量。
      
        1. 静态局部变量  
        它与局部变量的区别在于: 在函数退出时, 这个变量始终存在, 但不能被其它  
    函数使用, 当再次进入该函数时, 将保存上次的结果。其它与局部变量一样。  

        2. 静态全程变量  
       静态全程变量就是指只在定义它的源文件中可见而在其它源文件中不可见的变量。
    它与全程变量的区别是: 全程变量可以再说明为外部变量(extern), 被其它源文件使
    用, 而静态全程变量却不能再被说明为外部的, 即只能被所在的源文件使用。 

     

     

     

    static变量与全局变量初始化都一样,只会初始化一次,也就是你在函数内创建这个变量的时候要是给过一次初值,每次调用函数时不会重新给这个变量幅值,它会保持上一次的值,所以在函数执行完成跳出该函数的时候被释放掉。
    static函数的作用是限制该函数的使用范围,也就是只有本函数内的其他函数可以调用static函数,不能被跨文件调用。另外一点就是其他C文件可以使用同一个用static修饰的函数名

     

     

     

    u8 KEY_Scan(u8 mode)
    {  
    static u8 key_up=1;//按键按松开标志 (只进行一次初始化)
    if(mode)key_up=1;  //支持连按  
    if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
    {
    delay_ms(10);//去抖动 
    key_up=0;
    if(KEY0==0)return KEY0_PRES;
    else if(KEY1==0)return KEY1_PRES;
    else if(WK_UP==1)return WKUP_PRES; 
    }else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;     
    return 0;// 无按键按下
    }

     

     

    以下为GPS局部程序 应用的为静态变量、

     

     

     

     


    //GPRS数据保存位置
    static char GPRS_Data[MAXRECVBUFF]={0};
    static int  GPRS_Dlen = 0;
    static u8   GPRS_Dtu_ConLock = 0;
     
    u8 RestartGprs = 0; //重启GPRS标志
     
    #if GU906GSM_EN
    //短信信息在SIM卡中的位置
    static char SIMDataID[5]=""; 
    struct user_simdata sim;
    #endif
     
    /*********************************************************
      * @function  GPRS_ascii_to_hex
      * @role      
      * @input     
      * @output    None
      * @return    
      ********************************************************/
    static int GPRS_ascii_to_hex(u8 *asc_data, u8 *hex_data, int len)
    {
        int i;
        u8 tmp_dat;
        for(i = 0; i < len; i++)
        {
            if ((asc_data[i] >= '0') && (asc_data[i] <= '9')){
                tmp_dat = asc_data[i] - '0';
            }else if ((asc_data[i] >= 'A') && (asc_data[i] <= 'F')){ // A....F
                tmp_dat = asc_data[i] - 0x37;
            }
            else if((asc_data[i] >= 'a') && (asc_data[i] <= 'f')){ // a....f
                tmp_dat = asc_data[i] - 0x57;
            }else return -1;
            hex_data[i] = tmp_dat;  
        }
        return 0;
    }
     
    /*********************************************************
      * @function  mypow
      * @role      pow库函数的实现,计算num的n次幂,其中n为整数 
      * @input     num
      * @output    n
      * @return    计算结果
      *******************************************************
    static int mypow(int num,int n)
    {
        int powint=1;
        int i;
        for(i=1;i<=n;i++) powint*=num;
        return powint;
    }
    */
    /*********************************************************
      * @function  FreeStr
      * @role      删除字符串中的字串,支持16进制数据,无视结束符
      * @input     字符串、字符串总长度、开始删除的起始位置、要删除的长度
      * @output    None
      * @return    None
      ********************************************************/
    static void FreeStr(char *str, int strsiz, int head, int len)
    {
        int i = 0;
        while(len--)
        {
            for(i = head; i < strsiz;i++)
            {
                str[i] = str[i+1];
            }
        }
    }
     
    #if GU906GSM_EN
    /*********************************************************
      * @function  GU906_ParsingSIM
      * @role      解析SIM卡中的短信数据
      * @input     卡中的数据
      * @output    None
      * @return    成功返回:0,失败返回:-1
        @data      
        +CMGR: "REC READ","18750******",,"2015/03/14 20:02:15+32"
         124abcABC
        OK
      ********************************************************/
    static int GU906_ParsingSIM(char *pinput)
    {
        char *p = pinput;
        int i;
        #if DEBUG_EN
        printf("\n分离手机号\n");
        #endif
        if((p = strstr(p,"\",\"")) == 0)
            return -1;
        p += 3;
        memset(sim.phone,0,sizeof(sim.phone));
        for (i = 0; (*p != '\"') && (*p != '\0'); ++i,p++){
            sim.phone[i] = *p;
        }
        sim.phone[i] = '\0';
        #if DEBUG_EN
        printf("sms.phone[%s]\r\n",sim.phone);
        printf("\n分离设备类型\n");
        #endif
        
        p +=2;
        memset(sim.dev,0,sizeof(sim.dev));
        for (i = 0; (*p != ',') && (*p != '\0'); ++i,p++){
            sim.dev[i] = *p;
        }
        #if DEBUG_EN
        printf("sms.dev[%s]\r\n",sim.dev);
        printf("\n分离时间\n");
        #endif
        
        p += 2;
        memset(sim.date,0,sizeof(sim.date));
        for (i = 0; (*p != '\"') && (*p != '\0'); ++i,p++){
            sim.date[i] = *p;
        }
        #if DEBUG_EN
        printf("sms.date[%s]\r\n",sim.date);
        printf("\n分离数据\n");
        #endif
        
        p++;
        memset(sim.data,0,sizeof(sim.data));
        while((*p != '\0') && ((*p == '\n') || (*p == '\r')) ) p++;
        for (i = 0; (*p != '\0') && (*p != '\n') && (*p != '\r'); ++i,p++){
            sim.data[i] = *p;
        }
        sim.data[i] = '\0';
        #if DEBUG_EN
        printf("sms.data:[%s]\r\n",sim.data );
        #endif
        return 0;
    }
    #endif
     
    /*********************************************************
      * @function  GetRecvData
      * @role      提取字符串中跟命令无关的数据,有时在进行命令操作时,
                   会突然收到短信,什么的,这里要做的就是处理并过滤掉这些数据。
                   还有模块突然复位了,这里也做判断,并复位CPU。
      * @input     数据和数据长度
      * @output    None
      * @return    None
      ********************************************************/
    static void GetRecvData(char *pBuff, int *pLen)
    {
        int rlen = 0;
        char buff[5]="";
        int i = 0;
        char *p1 = NULL;
        char *p2 = NULL;    
     
        if((pBuff == NULL) || (*pLen == 0))
            return;
        if (((p1 = strstr(pBuff, "+IPD,")) != 0) && ((p2 = strchr(pBuff, ':')) != 0))
        {
            p1+=5;
            for (i = 0; ((p1-pBuff) < *pLen) && (i < 5) && (*p1 != ':'); ++i,++p1) {
                buff[i] = *p1;
            }
            buff[i] = '\0';
            rlen = atoi(buff);
            p2++;
            GPRS_Dlen = ((rlen >= (*pLen - (p2 - pBuff)))?(*pLen - (p2 - pBuff)):rlen);
            memcpy(GPRS_Data, p2,GPRS_Dlen);
            rlen = GPRS_Dlen;
            
            p1 = strstr(pBuff, "+IPD,");
            p2 = strchr(pBuff, ':');
            rlen += ((p2+1)-p1);
            FreeStr(pBuff, *pLen,p1-pBuff, rlen);
            if((*pLen -rlen) <=3)
                *pLen = 0;
            else
                *pLen -=rlen;
            #if DEBUG_EN
            printf("B[%d][%s]\r\n",*pLen, pBuff);
            #endif
        }
        #if GU906GSM_EN
        else if (strstr(pBuff, "+CMTI:") && ((p1 = strchr(pBuff, ',')) != 0)){   //+CMTI: "SM",2 有短信消息到来  
            rlen = 0;
            p1++;
            for(i = 0; *p1 != '\r' && *p1 != '\n' && *p1 != '\0' && rlen < sizeof(SIMDataID);i++, p1++){
                if(*p1 >= '0' && *p1 <= '9')
                    SIMDataID[rlen++] = *p1;
            }
            SIMDataID[rlen] = '\0'; 
        }
        else if ((p1 = strstr(pBuff, "+CMGR:")) != 0){ //读取到短消息
            GU906_ParsingSIM(p1);
        }
        #endif
        else if(strstr(pBuff,"[0000]") || strstr(pBuff,"Build Time")) 
        {
            #if (DEBUG_EN == 1)
            printf("restart...\r\n\r\n");
            #endif
            RestartGprs = 1;
        }
    }
     
    /*********************************************************
      * @function  GetFreeBuff
      * @role      处理掉缓存中多余的数据,同时也起到延时200ms的作用,
                   读取数据函数自带延时10ms,所以这里num=20,
                   GU906发送命令不能太快,不然GU906会因为处理不过来,而导致出错。
      * @input     None
      * @output    None
      * @return    None
      ********************************************************/
    static void GetFreeBuff(int num)
    {
        char buff[MAXRECVBUFF] = {0};
        int siz = 0;
        while(num--)
        {
            siz = usart4_Receive(buff,MAXRECVBUFF);
            if(siz)
            {
                GetRecvData(buff, &siz);    
            }
        }
    }
     
        
    /*********************************************************
      * @function  SendAT
      * @role      发送AT指令并接收
      * @input     gprs:要发送的参数
      * @output    out:返回的参数
      * @return    成功返回:_ATOK,失败返回:_ATERROR
      ********************************************************/
    static s8 SendAT(struct GprsData *gprs, char *out, u32 Delay)
    {
        int siz = 0;
        int i = 0;
        char *p = gprs->order;  
        u8 dat[2];
        u8 csq = 0;
        s8 ret = _ATERROR;
        char buff[MAXRECVBUFF] = {0};
        RestartGprs = 0;
     
    #if (DEBUG_EN == 1)
        printf("\r\n------------------------------\r\n");
        printf("len[%d]\r\n", gprs->olen);
        for(i = 0; i< gprs->olen; i++,++p)
            printf("%c", *p);
        printf("\r\n");
    #endif
        i = 0;
        p = NULL;
        GetFreeBuff(10);
        usart4_Send(gprs->order,gprs->olen);
        if((gprs->type == _GSMSEND) || (gprs->type == _ATATD)) 
        {
            ret = _ATOK;
            goto GU906_SENDATRET;
        }
     
        while(1)
        {
            for(i = 0;i<sizeof(buff);i++) 
                buff[i]=0;
            siz = 0; i = 0;
            while(siz == 0)
            {
                siz = usart4_Receive(buff,MAXRECVBUFF);
                if(siz){
                    #if (DEBUG_EN == 1)
                    printf("\r\nrecv:\r\n");
                    printf("[%s]\r\n",buff);
                    #endif
                    GetRecvData(buff, &siz);
                }
                if(i++ > Delay) 
                {
                    ret = _ATOTIME;
                    goto GU906_SENDATRET;
                }
            }
            
            if(RestartGprs){
                ret = _ATERROR;
                goto GU906_SENDATRET;
            }
            
            switch(gprs->type)
            {
                case _AT:
                case _ATE:   
                case _ATCNMI:
                case _ATCMGD:
                case _ATCMGF:
                case _ATCSMP:
                case _ATUCS2:
                case _ATATH :
                case _ATGSM :
                case _ATCSTT:
                case _ATCIICR:
                case _ATCIPCFG:
                case _ATCIPPACK:
                case _ATCIPSCONT:
                case _OPENDTU:
                case _CLOSEDTU:
                case _ATGB2312:
                    if(strstr(buff, "OK")){
                        ret = _ATOK;
                        goto GU906_SENDATRET;
                    }else if(strstr(buff, "ERROR") || strstr(buff,"NO CARRIER")) {
                        GetFreeBuff(100);
                        ret = _ATERROR;
                        goto GU906_SENDATRET;
                    }
                break;
                    
                case _ATCPMS:
                    if(strstr(buff, "OK") && strstr(buff, "+CPMS:")){
                         ret = _ATOK;
                         goto GU906_SENDATRET;
                    }else if(strstr(buff, "ERROR")){
                        ret = _ATERROR;
                        goto GU906_SENDATRET;
                    }
                    break;
                    
                case _ATESIM:
                    ret = _ATERROR;
                    if(strstr(buff, "OK"))
                    {
                        if((p = strstr(buff, "+ESIMS: ")) != 0)
                        {
                            p += 8;
                            if(1 == (*p -'0'))
                                ret = _ATOK;    
                        }
                        goto GU906_SENDATRET;
                    }
                    break;
                
                case _ATCMGS:
                    if(strstr(buff, ">")){
                        GetFreeBuff(1);
                        ret = _ATOK;
                        goto GU906_SENDATRET;
                    }
                    break;
     
                case _ATCSQ:
                    if(strstr(buff, "OK"))
                    {
                        if((p = strstr(buff, "+CSQ:")) != 0)
                        {
                            GPRS_ascii_to_hex((u8 *)(p+6), dat, 2);
                            csq = dat[0]*10 + dat[1];
                            #if DEBUG_EN
                            printf("信号:[%d]\r\n", csq);
                            #endif    
                            if (csq < 99 && csq >= GPRSCSQ){ //网络信号要大于GPRSCSQ(18)
                                ret = _ATOK;
                                goto GU906_SENDATRET;
                            } else {
                                ret = _ATERROR;
                                goto GU906_SENDATRET;
                            }    
                        }
                    }
                    else{
                        ret = _ATERROR;
                        goto GU906_SENDATRET;
                    }
                    break;
     
                case _ATCIPSTARTOK:
                    if(strstr(buff, "OK"))
                    {
                        if (strstr(buff, "+CIPSTART:")) {
                            ret = _ATOK;
                            goto GU906_SENDATRET;
                        }    
                        ret = _ATERROR;
                        goto GU906_SENDATRET;                    
                    }else if(strstr(buff, "ERROR")) {
                        ret = _ATERROR;
                        goto GU906_SENDATRET;
                    }
                    break;                
                
                case _ATCREG:
                    if(strstr(buff, "OK"))
                    {
                        if ((p = strstr(buff, "+CREG: ")) != 0)
                        {
                            p += 7;
                            if(('0' == *p) || ('5' == *p)) 
                            {
                                ret = _ATOK;
                                goto GU906_SENDATRET;
                            }
                        }    
                        ret = _ATERROR;
                        goto GU906_SENDATRET;                    
                    }else if(strstr(buff, "ERROR")) {
                        ret = _ATERROR;
                        goto GU906_SENDATRET;
                    }
                    break;
     
                case _ATCIPSEND:
                    if (strstr(buff, ">")) {
                        ret = _ATOK;
                        goto GU906_SENDATRET;
                    }
                    else if (strstr(buff, "ERROR")){
                        ret = _ATERROR;
                        goto GU906_SENDATRET;
                    }
                break;
     
                case _ATCIPMUX:
                    if(strstr(buff, "+CIPMUX: 0") && strstr(buff, "OK")) {
                        ret = _ATOK;
                        goto GU906_SENDATRET;
                    }else if (strstr(buff, "ERROR")){
                        ret = _ATERROR;
                        goto GU906_SENDATRET;
                    }
                    break;
     
                case _ATCIPMODE:
                    if(strstr(buff, "+CIPMODE: ") && strstr(buff, "OK")) {
                        ret = _ATOK;
                        goto GU906_SENDATRET;
                    }else if (strstr(buff, "ERROR")){
                        ret = _ATERROR;
                        goto GU906_SENDATRET;
                    }
                    break;
     
                case _GPRSSEND:
                    if(strstr(buff, "SEND OK")) {
                       ret = _ATOK;
                       goto GU906_SENDATRET;
                    }
                break;
     
                case _ATCMGR:
                    GetRecvData(buff, &siz);
                    ret = _ATOK;
                    goto GU906_SENDATRET;
                //break; 
     
                case _ATCIPCLOSE:
                    if (strstr(buff, "CLOSE OK") || strstr(buff, "+CME ERROR:")) {
                        ret = _ATOK;
                        goto GU906_SENDATRET;
                    }
                    else if(strstr(buff, "ERROR")){
                        ret = _ATERROR;
                        goto GU906_SENDATRET;   
                    }
                break;
     
                case _ATCIPSTART:
                    if(!GPRS_Dtu_ConLock)
                    {
                        if(strstr(buff, "CONNECT OK")){
                            ret = _ATOK;
                            goto GU906_SENDATRET;
                        }
                        else if(strstr(buff, "RECONNECTING") || strstr(buff, "ERROR") || strstr(buff, "CONNECT FAIL")){
                            GetFreeBuff(100);
                            ret = _ATERROR;
                            goto GU906_SENDATRET;
                        }                    
                    }
                    else if(strstr(buff, "OK")){
                        ret = _ATOK;
                        goto GU906_SENDATRET;
                    }
                    else if(strstr(buff, "ERROR")){
                        ret = _ATERROR;
                        goto GU906_SENDATRET;   
                    }
                    break;
                
                case _GSMSENDEND: 
                    GetFreeBuff(100);
                    ret = _ATOK;
                    goto GU906_SENDATRET; //忽略返回信息
                    /*
                    if(strstr(buff, "+CMGS:")) {
                        if(strstr(buff, "OK"))
                            return _ATOK;
                        lock = 1;
                    }
                    else if(lock && strstr(buff, "OK")) {
                        return _ATOK;
                    }else return _ATOK; //忽略返回信息
                    break;
                    */
                case _ATCIPSCONT_C:
                    if(strstr(buff,"OK"))
                    {
                        printf("Line:%d\r\n",__LINE__);
                        if(0 != (p = strstr(buff,"+CIPMODE: ")))
                        {
                            p += 10;
                            printf("Line:%d\r\n",__LINE__);
                            if(1 == (*p -'0'))
                            {
                                printf("Line:%d\r\n",__LINE__);
                                if(0 != (p = strstr(buff,"+CIPSTART: ")))
                                {
                                    printf("Line:%d\r\n",__LINE__);
                                    if(strstr(buff,"218.66.59.201") && strstr(buff,"8888"))
                                    {
                                        printf("DTU OK\r\n");
                                        GPRS_Dtu_ConLock = 1;
                                        ret = _ATOK;
                                        goto GU906_SENDATRET;
                                    }
                                }                        
                            }
                        }
                        GPRS_Dtu_ConLock = 0;
                        ret = _ATOK;
                        goto GU906_SENDATRET;
                    }else if(strstr(buff, "ERROR")){
                        ret = _ATERROR;
                        goto GU906_SENDATRET;   
                    }
                    break;
                    
                default: break; 
            }   
        }
        GU906_SENDATRET:
        return ret;
    }
     
    /*********************************************************
      * @function  GU906_ExecuteOrder
      * @role      执行命令
      * @input     None
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    static s8 GU906_ExecuteOrder(char *Order, u32 len, enum order type, u32 num)
    {
        u32 i = 0;
        u32 delay_time = 1000;
        s8 ret = _ATOTIME;
        struct GprsData gprs;
        
        if(type == _ATCIPSTART)
            delay_time = 4000;
        if(type == _GPRSSEND)
            delay_time = 10;
        
        gprs.order = Order;
        gprs.olen = len;
        gprs.type = type;
        while((ret = SendAT(&gprs, NULL, delay_time)) != _ATOK)
        {
            if(ret == _ATERROR) {
                if(++i >= num) return _ATERROR;
                delay_s(1);
            }else return _ATOTIME;
        }
        return _ATOK;
    }
     
    /*********************************************************
      * @function  GU906_init
      * @role      GSM初始化
      * @input     None
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_init(void)
    {
        s8 ret = _ATOTIME;
     
        // 开回显:ATE1 关回显:ATE0
        if(_ATOK != (ret = GU906_ExecuteOrder(ATE(0), strlen(ATE(0)), _ATE, 2)))
            return ret;
        
        // 查询卡是否存在
        if(_ATOK != (ret = GU906_ExecuteOrder(ATESIM, strlen(ATESIM), _ATESIM, 10))) 
            return ret;
     
    #if GU906GSM_EN
        // 设置短信模式为text模式
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCMGF, strlen(ATCMGF), _ATCMGF, 2))) 
            return ret;
     
        // 设置短信存储单元为SIM卡
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCPMS, strlen(ATCPMS), _ATCPMS, 2))) 
            return ret;
     
        // 设置这组参数来了新信息存储起来
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCNMI, strlen(ATCNMI), _ATCNMI, 2))) 
            return ret;
    #endif
        
        //删除SIM卡中的所有短信
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCMGD, strlen(ATCMGD), _ATCMGD, 2))) 
            return ret;
     
        //查询信号强度 信号强度大于等于18才行
        while(_ATOK != (ret = GU906_ExecuteOrder(ATCSQ, strlen(ATCSQ), _ATCSQ, 60)))
        {
            if(ret == _ATOTIME) return ret;
        }
        return _ATOK;  
    }
     
    /*********************************************************
      * @function  GU906_Module_State
      * @role      判断GU906的状态
      * @input     None
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_Module_State(void)
    {
        return GU906_ExecuteOrder(AT, strlen(AT), _AT, 0);
    }
     
    /*********************************************************
      * @function  GU906_TCP_Socket
      * @role      进行TCP连接
      * @input     IP地址与端口
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_TCP_Socket(struct Gprs_Config *GprsCon)
    {
        char cipstart[100] = {0};
        s8 ret = _ATOTIME;
        
        if(GprsCon->server_ip == NULL || !GprsCon->server_port) return ret;
        if(!strlen((char *)GprsCon->server_ip)) return ret;
        
        //确保模块以及注册到GSM网络
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCREG, strlen(ATCREG), _ATCREG, 2))) 
            return ret;
     
        //让模块激活 GPRS 网络,在需要反复建立 TCP 链接的场合可提高速度
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCIICR, strlen(ATCIICR), _ATCIICR, 2))) 
            return ret;
        
        //查询当前是否有网络连接
        while(_ATOK == GU906_ExecuteOrder(ATCIPSTARTOK, strlen(ATCIPSTARTOK), _ATCIPSTARTOK, 0)) 
        {
            //关闭网络连接
            if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPCLOSE, strlen(ATCIPCLOSE), _ATCIPCLOSE, 2))) 
                return ret;
            
            //保存设置
            if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPSCONT(0), strlen(ATCIPSCONT(0)), _ATCIPSCONT, 2))) 
                return ret;
        }
     
        //单链接模式
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPMUX, strlen(ATCIPMUX), _ATCIPMUX, 2))) 
            return ret;
     
        //非数据透传输模式
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPMODE(0), strlen(ATCIPMODE(0)), _ATCIPMODE, 2))) 
            return ret;
     
        //自动启动连接命令
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPCFG(0), strlen(ATCIPCFG(0)), _ATCIPCFG, 2))) 
            return ret;
     
        //心跳包设置
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPPACK(0), strlen(ATCIPPACK(0)), _ATCIPPACK, 2))) 
            return ret;
        
        //连接到服务器
        //cipstart=(char *)mymalloc(100); 
        //if(cipstart==NULL) return -1; 
        sprintf(cipstart, ATCIPSTART,"TCP", GprsCon->server_ip, GprsCon->server_port);
        ret = GU906_ExecuteOrder(cipstart, strlen(cipstart), _ATCIPSTART, 3);
        
        //myfree(cipstart);
        return ret;
    }
     
    /*********************************************************
      * @function  GU906_DTU_Socket
      * @role      设置透传模式
      * @input     IP地址与端口
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_DTU_Socket(struct Gprs_Config *GprsCon)
    {
        char atorder[100] = "";
        s8 ret = _ATOTIME;
        
        if(GprsCon->server_ip == NULL || !GprsCon->server_port) return ret;
        if(!strlen((char *)GprsCon->server_ip)) return ret;
        
        //atorder=(char *)mymalloc(100); 
        //if(atorder==NULL) return -1; 
        
        //查询数据透设置情况
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPSCONT_C, strlen(ATCIPSCONT_C), _ATCIPSCONT_C, 2))) 
            goto GU906_DTU_SOCKETEND;
     
        if(!GPRS_Dtu_ConLock)
        {
            //设置账号
            if(_ATOK != (ret = GU906_ExecuteOrder(ATCSTT, strlen(ATCSTT), _ATCSTT, 2))) 
                goto GU906_DTU_SOCKETEND;
            
            //透传参数设置
            if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPCFG(1), strlen(ATCIPCFG(1)), _ATCIPCFG, 2))) 
                goto GU906_DTU_SOCKETEND;
            
            //设置心跳
            if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPPACK(0), strlen(ATCIPPACK(0)), _ATCIPPACK, 2))) 
                goto GU906_DTU_SOCKETEND;
            
            //设置设备注册包
            if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPPACK(1), strlen(ATCIPPACK(1)), _ATCIPPACK, 2))) 
                goto GU906_DTU_SOCKETEND;
            
            //单链接模式
            if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPMUX, strlen(ATCIPMUX), _ATCIPMUX, 2))) 
                goto GU906_DTU_SOCKETEND;
     
            //数据透传输模式
            if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPMODE(1), strlen(ATCIPMODE(1)), _ATCIPMODE, 2))) 
                goto GU906_DTU_SOCKETEND;
     
            //保存设置
            sprintf(atorder, ATCIPSCONT(1),"TCP", GprsCon->server_ip, GprsCon->server_port);
            if(_ATOK != (ret = GU906_ExecuteOrder(atorder, strlen(atorder), _ATCIPSCONT, 2))) 
                goto GU906_DTU_SOCKETEND;
            
            GPRS_Dtu_ConLock = 1;
        }
     
        //建立数据透连接
        sprintf(atorder, ATCIPSTART, "TCP", GprsCon->server_ip, GprsCon->server_port);
        if(_ATOK != (ret = GU906_ExecuteOrder(atorder, strlen(atorder), _ATCIPSTART, 2))) 
            goto GU906_DTU_SOCKETEND;
     
        GU906_DTU_SOCKETEND:
        //myfree(atorder);
        return ret;
    }
     
    /*********************************************************
      * @function  GU906_DtuOrAT
      * @role      透传模式与AT模式转换
      * @input     None
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_DtuOrAT(u8 type)
    {
        s8 ret = _ATERROR;
        if(type)
        {
            while(!GPRS_Dtu_ConLock)
            {
                //打开透传
                delay_s(2);
                if(_ATOK != (ret = GU906_ExecuteOrder(OPENDTU, strlen(OPENDTU), _OPENDTU, 0))) 
                    goto GU906_DTUOFFONEND;
                GPRS_Dtu_ConLock = 1;
            }
        }
        else
        {
            while(GPRS_Dtu_ConLock)
            {
                //关闭透传
                delay_s(2);
                if(_ATOK != (ret = GU906_ExecuteOrder(CLOSEDTU, strlen(CLOSEDTU), _CLOSEDTU, 0)))
                {
                    delay_s(1);
                    if(_ATOK != (GU906_Module_State()))
                        goto GU906_DTUOFFONEND;    
                }
                GPRS_Dtu_ConLock = 0;
            }    
        }
        
        GU906_DTUOFFONEND:
        return ret;
    }
    /*********************************************************
      * @function  GU906_GPRS_write
      * @role      gprs发送数据
      * @input     要发送的数据与数据长度
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_GPRS_write(char* pdat, int len)
    {
        char atorder[20] = "";
        s8 ret = -1;
        if(strlen(pdat) == 0) return 0;
        
        //atorder = (char *)mymalloc(20); 
        //if(atorder == NULL) return -1; 
        
        if(!GPRS_Dtu_ConLock)//非数据透模式
        {
            //设置数据长度
            sprintf(atorder, ATCIPSEND(1), len);
            if(_ATOK != (ret = GU906_ExecuteOrder(atorder, strlen(atorder), _ATCIPSEND, 0))) 
                goto GU906_GPRS_WRITERET;
            
            //发送数据
            if(_ATOK != (ret = GU906_ExecuteOrder(pdat, len, _GPRSSEND, 0))) 
                goto GU906_GPRS_WRITERET;
        }
        else
        {
            //发送数据
            usart4_Send(pdat, len);
            ret = _ATOK;
        }
        GU906_GPRS_WRITERET:
        //myfree(atorder);
        return ret;
    }
     
    /*********************************************************
      * @function  GU906_GPRS_read
      * @role      查询是否接收到数据
      * @input     输出缓存大小
      * @output    接收到的数据
      * @return    接收到的数据长度
      ********************************************************/
    u32 GU906_GPRS_read(char *pout, int len)
    {
        int i = 0;
        
        if(!GPRS_Dtu_ConLock)
        {
            GPRSREAD:
            if(GPRS_Dlen){
                for(i = 0;(i < GPRS_Dlen) && (i < (len -1)); i++){
                    pout[i] = GPRS_Data[i];
                }
                memset(GPRS_Data, 0, sizeof(GPRS_Data));
                GPRS_Dlen = 0;
                return i;
            }else{
                GetFreeBuff(1);
                if(GPRS_Dlen)
                    goto GPRSREAD;
            }    
        }
        else
        {
            return usart4_Receive(pout,len);
        }
        return 0;
    }
     
    /*********************************************************
      * @function  GU906_make_phone
      * @role      向指定的手机拨号
      * @input     手机号
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_make_phone(char *phone)
    {
        char mphone[20]="";
        sprintf(mphone, ATATD, phone);  
        return GU906_ExecuteOrder(mphone, strlen(mphone), _ATATD, 0);
    }
     
    /*********************************************************
      * @function  GU906_Answer_Phone
      * @role      等待电话被接听
      * @input     手机号
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_Answer_Phone(u32 Delay)
    {
        int siz = 0;
        u32 i = 0;
        char buff[MAXRECVBUFF] = "";
        
        i = 0;
        while(1)
        {
            siz = 0;
            siz = usart4_Receive(buff,MAXRECVBUFF);
            if(siz){
                GetRecvData(buff, &siz);
                if(strstr(buff, "+COLP:") && strstr(buff, "OK")){
                    return _ATOK;
                }else if(strstr(buff, "NO CARRIER") || strstr(buff, "+CREG: 1") || strstr(buff, "ERROR")){
                    return _ATERROR;
                }
            }
            if(i++ > Delay) 
            {
                return _ATOTIME;
            }
        }
    }        
    /*********************************************************
      * @function  GU906_end_phone
      * @role      挂机
      * @input     None
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_end_phone(void)
    {
        return GU906_ExecuteOrder(ATATH, strlen(ATATH), _ATATH, 0);
    }
     
    #if GU906GSM_EN
    /*********************************************************
      * @function  GU906_Chinese_text
      * @role      向指定的手机发送中文短信
      * @input     phone 手机号指针,pmsg 短消息指针
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME
      ********************************************************/
    s8 GU906_Chinese_text(char *phone,char* pmsg)
    {
        s8 ret = _ATOTIME;
        char atphone[50] = "";
        char end[]={0x1A,0x00};
        
        if(strlen(phone) != 11)  return _ATERROR;
        //atphone = (char *)mymalloc(50); 
        //if(atphone == NULL) return -1; 
        
        //设置短消息为txet模式
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCMGF, strlen(ATCMGF), _ATCMGF, 2))) 
            goto GU906_CHINESE_TEXTEND;
        
        //设置GB2312编码
        if(_ATOK != (ret = GU906_ExecuteOrder(ATGB2312, strlen(ATGB2312), _ATGB2312, 2))) 
            goto GU906_CHINESE_TEXTEND;
        
        //设置这组参数来了新信息存储起来 
        if(_ATOK != (ret = GU906_ExecuteOrder(ATCNMI, strlen(ATCNMI), _ATCNMI, 2))) 
            goto GU906_CHINESE_TEXTEND;
        
        //设置用户手机号
        sprintf(atphone,ATCMGS,phone);
        if(_ATOK != (ret = GU906_ExecuteOrder(atphone, strlen(atphone), _ATCMGS, 2))) 
            goto GU906_CHINESE_TEXTEND;
        
        //发送数据
        if(_ATOK == (ret = GU906_ExecuteOrder(pmsg, strlen(pmsg), _GSMSEND, 0))) 
        {
            ret = GU906_ExecuteOrder(end, 1, _GSMSENDEND, 0);
        }
        GU906_CHINESE_TEXTEND:
        //myfree(atphone);
        return ret;
    }
     
    /*********************************************************
      * @function  GU906_Read_SIM
      * @role      读取短信信息
      * @input     短信在SIM卡中的位置
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME 
      ********************************************************/
    static s8 GU906_Read_SIM(char *pnum)
    {
        s8 ret = _ATOTIME;
        char cmgr[20]="";
        //读取短信的编码格式为GB2312
        if(_ATOK != (ret = GU906_ExecuteOrder(ATGB2312, strlen(ATGB2312), _ATGB2312, 2))) 
            return ret;
        
        //读取短消息
        sprintf(cmgr,ATCMGR,pnum);
        return GU906_ExecuteOrder(cmgr, strlen(cmgr), _ATCMGR, 2);
    }
     
    /*********************************************************
      * @function  GU906_DeleteSms
      * @role      删除SIM卡中的所有短信
      * @input     None
      * @output    None
      * @return    成功返回:_ATOK,失败返回:_ATERROR,超时返回:_ATOTIME 
      ********************************************************/
    static int GU906_DeleteSms(void)
    {
        return GU906_ExecuteOrder(ATCMGD, strlen(ATCMGD), _ATCMGD, 2);
    }
     
    /*********************************************************
      * @function  GU906_Read_UserSMS
      * @role      查询并读取短信数据
      * @input     None
      * @output    None
      * @return    0,接收到新数据,-1,未接收到新数据
      ********************************************************/
    s8 GU906_Read_UserSMS(void)
    {
        SMSREAD:
        if(strlen(SIMDataID)){
            #if DEBUG_EN
            printf("SIMDataID[%s]\r\n",SIMDataID);
            #endif
            GU906_Read_SIM(SIMDataID);
            GU906_DeleteSms();
            memset(SIMDataID,0,sizeof(SIMDataID));
            return 0;
        }else{
            GetFreeBuff(1);
            if(strlen(SIMDataID))
                goto SMSREAD;
        }
        return -1;
    }
    #endif

    gu906.文件如下
    #ifndef _GU906_H_
    #define _GU906_H_
    #include "sys.h"
     
    #define GU906GSM_EN   1    //是否开启短信功能 
    #define GPRSCSQ       18   //信号强度,在使用GPRS功能时,最低要求信号强度不得低于18
     
    #define _ATOK          0  //执行成功
    #define _ATERROR      -1  //执行错误
    #define _ATOTIME      -2  //执行超时
    #define _LINKNOT      -3  //掉线了
     
    struct Gprs_Config{
        u8 *server_ip;     //服务器IP
        u32 server_port;   //服务器端口
    };
     
    #if GU906GSM_EN
    //根据实际内存情况而定
    struct user_simdata{
        char phone[15];  //用户手机号
        char dev[50];    //用户使用的设备
        char date[50];   //接收时间
        char data[200];  //接收的数据
    };
    extern struct user_simdata sim;
    s8 GU906_Read_UserSMS(void);
    s8 GU906_Chinese_text(char *phone,char* pmsg);
    #endif
     
    s8  GU906_init(void);
    s8  GU906_Module_State(void);
    s8  GU906_TCP_Socket(struct Gprs_Config *GprsCon);
    s8  GU906_DTU_Socket(struct Gprs_Config *GprsCon);
    s8  GU906_GPRS_write(char* pdat, int len);
    u32 GU906_GPRS_read(char *pout, int len);
     
    s8  GU906_make_phone(char *phone);
    s8  GU906_Answer_Phone(u32 Delay);
    s8  GU906_end_phone(void);
    s8  GU906_DtuOrAT(u8 type);
     
     
    #endif
    main.c

    #include <string.h>
    #include <stdlib.h>
    #include "stdio.h"
    #include "delay.h"
    #include "GU906.h"
    #include "config.h"
    #include "usart1.h"
    #include "usart4.h"
     
    int main(void)
    {    
        u32 ret = 0;
        char buff[200]="";
        struct Gprs_Config GprsCon;
        delay_init();
        usart4_Configuration(115200);    //GU900默认通信波特率是115200
        usart1_Configuration(115200);    //调试输出端口波特率设置
        delay_s(5);                      //刚上电 要等待10秒,等待GU906模块初始化完成
        
        printf("\r\nBegin...\r\n");
        GprsCon.server_ip = (u8 *)"210.66.59.211"; //GPRS通信时的服务器IP
        GprsCon.server_port = atoi("8888");        //GPRS通信时的服务器端口
        
        //GSM初始化
        while(1)
        {
            if(_ATOK == GU906_init()){
                printf("GU906 init ok.\r\n\r\n");
                break;
            }
            printf("init error.\r\n");
            delay_s(1);
        }
        
        /*****************************************************************************/
        //GU906 GPRS TCP 非透传模式通信测试
        while(1)
        {
            if(_ATOK == GU906_TCP_Socket(&GprsCon))
            {
                printf("socket ok\r\n\r\n");
                delay_s(3);    
                while(1)
                {
                    ret = GU906_GPRS_read(buff, 200);
                    if(ret)
                    {
                        printf("GPRS:[%d][%s]\r\n", ret,buff);
                        if(_ATOK != GU906_GPRS_write((char *)"OK", 2))
                        {
                            printf("Send Error.\r\n");
                        }                    
                    }
                }
            }
            printf("GU906_TCP_Socket ERROR.\r\n");
            while(1);
        }
        /*******************************************************************************/
        
        /*****************************************************************************/
        //GU906 GPRS TCP 透传模式通信测试
        while(1)
        {
            if(_ATOK == GU906_DTU_Socket(&GprsCon))
            {
                printf("socket ok\r\n\r\n");
                delay_s(3);    
                while(1)
                {
                    ret = GU906_GPRS_read(buff, 200);
                    if(ret)
                    {
                        printf("GPRS:[%d][%s]\r\n", ret,buff);
                        if(_ATOK != GU906_GPRS_write((char *)buff, ret))
                        {
                            printf("Send Error.\r\n");
                        }                    
                        
                        if(strstr(buff,"CLOSE"))
                        {
                            GU906_DtuOrAT(0);
                        }
                        if(strstr(buff,"OPEN"))
                        {
                            GU906_DtuOrAT(1);
                        }
                    }
                }
            }
            printf("GU906_TCP_Socket ERROR.\r\n");
            while(1);
        }
        /*******************************************************************************/
        
        /*****************************************************************************/
        //发送短信测试
        while(_ATOK != GU906_Chinese_text("18750******", "123abd 测试"))
        {
            delay_s(5);
        }
     
        //接收短信测试
        while(1)
        {
            if(0 == GU906_Read_UserSMS())
            {
                printf("------------------------------\r\n");
                printf("号码:%s\r\n",sim.phone);
                printf("设备:%s\r\n",sim.dev);
                printf("时间:%s\r\n",sim.date);
                printf("信息:%s\r\n",sim.data);
            }
            delay_ms(50);
        }
        /******************************************************************************/
        
        /*****************************************************************************/
        //打电话测试
        if (_ATOK == GU906_make_phone("18750******"))
        {
            //等待接听
            while(_ATOTIME == GU906_Answer_Phone(1000))
            {
                printf("make ok\r\n");
                GU906_end_phone();            
            }
            printf("make ok\r\n");
        }
        else 
        {
            printf("make error\r\n");
            //SoftReset();
        }
     

    展开全文
  • 什么全局变量,局部变量,静态局部变量,静态全局变量 到这里,我们就可以很容易区分上面的变量类型了。实际上这里只是换了一种说法: 全局:具有文件作用域的变量 静态:具有静态存储期或内部链接属性 局部:具有...
  • C++中 静态局部变量实例详解 以前经常使用和了解static作用在全局变量前,以至于甚至把static当做全局变量的代名词,但是其实static还可以作用于局部变量前 静态局部变量的意义: 1.分配空间在全局数据栈上 2.作用...
  • 一种简单的单例模式,使用静态局部变量。 为什么是静态局部变量可以保证线程安全性? 原因是Magic Static特性。如果变量在初始化时,并发线程同时进入到static声明语句,并发线程会阻塞等待初始化结束。这样可以...
  • 变量可以分为全局变量、静态全局变量、静态局部变量和局部变量 按存储区域分:全局变量、静态全局变量和静态局部变量都存放在内存的全局数据区,局部变量存放在内存的栈区 按作用域分:全局变量在整个工程文件内都...
  • 静态局部变量和动态局部变量区别

    千次阅读 2020-05-13 10:03:05
    静态局部变量和动态局部变量区别: 1.静态局部变量属于静态存储类别,在静态存储区分配存储单元,在整个运行期间都不释放。 而自动变量(动态局部变量)属于动态存储类别,占动态存储空间,函数调用后释放 2.静态局部...
  • CC++中的静态全局变量,静态局部变量,全局变量,局部变量的区别
  • 最近看《C程序设计》第五版唐浩强著对静态局部变量有这样一段: > 对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的...
  • 在本篇文章里小编给大家整理的是关于易语言静态局部变量的相关知识点内容,有此需要的读者们可以参考学习下。
  • 局部变量在函数的开头定义在函数内的符合语句内定义作用范围在包含该局部变量的函数内有效一个函数内部,可以在复合函数语句中定义变量,这些变量只在本复合语句中有效,这种符合语句称为分程序或程序块 #include<...
  • C语言--静态局部变量

    2020-10-05 09:14:29
    静态局部变量也是定义在函数内部的,静态局部变量定义时前面要加static关键字来标识,静态局部变量所在的函数在多调用多次时,只有第一次才经历变量定义和初始化,以后多次在调用时不再定义和初始化,而是维持之前上...
  • 今天被问到了一个问题:如何让请求的类延迟释放如果要延迟释放或者在程序整个生命周期都存在可以考虑两种方式,一是定义一个静态变量,二是用单例。用单例本质上用的是静态变量。单例的写法如下:+ (instancetype)...
  • 静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。...
  • 关于静态局部变量与静态外部变量

    千次阅读 2017-11-09 19:14:10
    1:静态局部变量存储在静态存储区,如果赋有初值,函数调用期间只赋值一次,下次调用该函数时,静态局部变量值为上次调用之后的结果,原因:静态局部变量在函数调用期间是不释放的;而自动变量在每次调用函数时都会...
  • 变量可以分为:全局变量、静态全局变量、静态局部变量和局部变量。 按存储区域分,全局变量、静态全局变量和静态局部变量都存放在内存的静态 存储区域,局部变量存放在内存的栈区。 按作用域分,全局变量在整个...
  • 全局变量、static全局变量、static局部变量都在全局区(静态区),而局部变量在栈区。2.生命周期 全局变量、static全局变量、static局部变量都存在于程序的整个生命周期中;局部变量存在于函数执行期间,函数结束,...
  • 存放在全局数据区的变量的生存周期存在于整个程序运行期间,而存放在栈中的数据则随着函数等的作用域结束导致出栈而销毁,除了静态变量之外的局部变量都存放于栈中。 作用域: 变量的可见代码域(块作用域,函数作用...
  • 静态全局变量 作用域仅限于变量被定义的文件中,其他文件即使用 extern 声明也没法 使用他。准确地说作用域是从定义之处开始,到文件结尾处结束,在定义之处前面的那些 代码行也不能使用它。...静态局部变量 ...
  • 静态局部变量与自动局部变量的区别 区别: 1、静态局部变量属于静态存储类别,在静态存储区内分配存储分配单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储区...
  • 利用静态局部变量求阶乘

    千次阅读 2018-07-27 15:51:51
    可以利用静态局部变量在在内存中不自动释放的特性,去计算阶乘,详细代码如下: #include &lt;iostream&gt; using namespace std; long CalcResult(int num) { static int result = 1; result = num*...
  • C语言静态局部变量

    千次阅读 2016-11-19 20:20:14
    用static声明局部变量,有时我们希望局部...这时就应该指定该局部变量为“静态局部变量”,用关键字static进行声明。 #include int main() {  int fac(int n);  int i = 1;  for(i = 1; i  {  prin

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 327,924
精华内容 131,169
关键字:

静态局部变量