精华内容
下载资源
问答
  • 静态局部变量和静态全程变量static。

    万次阅读 多人点赞 2019-01-01 13:28:04
    static 是 C/C++ 中很常用的修饰符,它被用来控制变量的存储方式可见性。 1.1 static 的引入 我们知道在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此...

    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();
        }
     

    展开全文
  • JavaScript-语法、关键保留字及变量

    千次阅读 2017-09-24 14:31:03
    语法构成 区分大小写 标识符 ...例如:artisanArtisan表示两种不同的变量。标识符所谓标识符,就是指变量、函数、属性的名字,或者函数的参数。标识符可以是下列格式规则组合起来的一或多个字符: 1

    语法构成

    JavaScript 的语言核心 ECMAScript.

    区分大小写

    ECMAScript 中的一切,包括变量、函数名和操作符都是区分大小写的。

    例如:artisan和Artisan表示两种不同的变量。


    标识符

    所谓标识符,就是指变量、函数、属性的名字,或者函数的参数。

    标识符可以是下列格式规则组合起来的一或多个字符:

    • 1.第一字符必须是一个字母、下划线(_)或一个美元符号($)。

    • 2.其他字符可以是字母、下划线、美元符号或数字。

    • 3.不能把关键字、保留字、true、false 和 null 作为标识符。


    注释

    ECMAScript 使用 C 风格的注释,包括单行注释和块级注释。

    // 单行注释
    /*
    * 这是一个多行
    * 注释
    */

    直接量(字面量literal)

    所有直接量(字面量),就是程序中直接显示出来的数据值。

    • 100 //数字字面量

    • ’小工匠’ //字符串字面量

    • false //布尔字面量

    • /js/gi //正则表达式字面量

    • null //对象字面量

    在 ECMAScript 第 3 版中,像数组字面量和对象字面量的表达式也是支持的,如下:

    • {x:1, y:2} //对象字面量表达式

    • [1,2,3,4,5] //数组字面量表达式


    关键字保留字

    ECMAScript-262 描述了一组具有特定用途的关键字,一般用于控制语句的开始或结束 ,或者用于执行特定的操作等。关键字也是语言保留的,不能用作标识符。

    ECMAScript 全部关键字:
    这里写图片描述


    ECMAScript-262 还描述了另一组不能用作标识符的保留字。尽管保留字在 JavaScript中还没有特定的用途,但它们很有可能在将来被用作关键字。

    ECMAScript-262 第 3 版定义的全部保留字
    这里写图片描述


    变量

    ECMAScript 的变量是松散类型的,所谓松散类型就是用来保存任何类型的数据。定义变量时要使用 var 操作符(var 是关键),后面跟一个变量名(变量名是标识符)。

    var artisan;
    alert(artisan);

    这句话定义了 artisan变量,但没有对它进行初始化(也就是没有给变量赋值)。这时,系统会给它一个特殊的值 – undefined(表示未定义)。

    var artisan= '小工匠';
    alert(artisan);

    所谓变量,就是可以初始化后可以再次改变的量。ECMAScript 属于弱类型(松散类型)的语言,可以同时改变不同类型的量。(PS:虽然可以改变不同类型的量,但这样做对于后期维护带来困难,而且性能也不高,导致成本很高!)

    var artisanString= '小工匠';
    artisanString = 100;
    alert(artisanString);

    重复的使用 var 声明一个变量,只不过是一个赋值操作,并不会报错。但这样的操作是比较二的,没有任何必要。

    var artison= '小工匠';
    var artison= '小小工匠';

    还有一种变量不需要前面 var 关键字即可创建变量。这种变量和 var 的变量有一定的区别和作用范围。

    artison= '小工匠';

    当你想声明多个变量的时候,可以在一行或者多行操作。

    var artison= '小工匠'; var age= 100;

    而当你每条语句都在不同行的时候,你可以省略分号。(PS:这是 ECMAScript 支持的 ,但绝对是一个非常不好的编程习惯,切记不要)。

    var artison= '小工匠'
    var age= 100
    alert(artison)

    可以使用一条语句定义多个变量,只要把每个变量(初始化或者不初始化均可)用逗号分隔开即可,为了可读性,每个变量,最好另起一行,并且第二变量和第一变量对齐(PS:这些都不是必须的)。

    var artison= '小工匠',
        age = 28,
        height;
    展开全文
  • JS引用和变量

    千次阅读 2019-03-28 19:19:04
    JS引用和变量 开发工具与关键技术:VS JavaScript 作者:吴泽锋 撰写时间:2019年3月28日 1、JS引用 1.1、外部JS引用 直接在解决方案管理器里的Script,里面进行选择,把想要的JS选中直接拖进该视图要引用的位置...

    文献种类:专题技术文献;

                              JS引用和变量
    
    开发工具与关键技术:VS   JavaScript     
    作者:吴泽锋
    撰写时间:2019年3月28日
    

    1、JS引用
    1.1、外部JS引用
    直接在解决方案管理器里的Script,里面进行选择,把想要的JS选中直接拖进该视图要引用的位置<.script src="~/Script/Myjs.js"><./script>
    1.2、自定义JS使用,即内部JS引用;
    <.script> alert(“头部JS”); <./script>
    若想要在内容没有出来前JS实现的话,就放在头部;
    若想要在头部出来内容没有出来前JS实现的话,就放boyd下面即内容前面;
    一般情况下,为页面绑定数据,页面先出来再进行数据的绑定,则放在内容后面;
    <.script 旧版本的浏览器需要加: type=“text/javascript”> alert(“头部JS”);<./script>
    1.3、标签嵌套: 直接嵌套进HTML标签里使用,此方法不建议使用
    <.button style="" “alert(‘JS’)”><./button>
    <.button style="" “document.write(‘JS’)”><./button>
    注意:document.write会覆盖原有信息,alert点击弹出提示框,单双引号嵌套"’’"。
    2、变量: 变量是用于存储某种/某些数值的存储器
    2.1、变量声明: 声明变量语法: var 变量名;
    var mysum;一次声明一个变量
    可以在一条语句中声明多个变量。该语句以 var 开头,并使用逗号分隔变量即可:
    var mysum,mynum;一次声明多个变量
    未使用值来声明的变量,其值实际上是 undefined。以上两变量为例。
    注:变量也可以不声明,直接使用,但为了规范,需要先声明,后使用。
    向变量分配文本值时,应该用双引号或单引号包围这个值。
    向变量赋的值是数值时,不要使用引号。如果用引号包围数值,该值会被作为文本来处理。
    2.2、变量赋值: mynum=5;//赋值 var mynum=5;//声明变量mynum并赋值
    注:这里 "="号的作用是给变量赋值,不是等于号是赋值运算符。
    6种基本数据类型:
    1、String 字符串 2、Number 数字
    3、Bool 布尔 逻辑值 true, false 4、Object 对象
    5、Null 空 6、underfined 未定义 7、Array 数组特殊的Object
    2.3、变量命名: 一般采用小驼峰法命名
    var kgn = “MyClassName”; 大驼峰法
    var kgng = “myClassName”; 小驼峰法
    变量名可以任意取名,但要遵循命名规则;
    必需使用字母,下划线()或者美元符号()使线()()开始。 然后可以使用任意多个英文字母、数字、下划线(_)或者美元符号()组成。
    var _grqa=“ewg”; var $gaeg=“geg an”;
    不能使用JavaScript关键词与JavaScript保留字
    在JS中命名区分大小写,变量A与a是不一样的,表示两个变量。
    2.4、保留关键字
    abstract     arguments     boolean     break      byte      case      catch     class    
    continue     const      char      debugger     default     delete      do     double    
    extends      enum      eval      export      else      for      float     final    
    function     finally     false      goto      if      import      in     int    
    implements     instanceof     interface     let     long      native      new     null    
    protected     package      private      public      return      static     short     super    
    synchronized     switch     transient      throw      throws      true     this     try    
    typeof      volatile      void      var      while      with     yield
    2.5、按作用域划分:
    局部变量 :
    在 JavaScript 函数内部声明的变量(使用 var)是局部变量,只能在函数内部访问它。
    (该变量的作用域是局部的)。可以在不同的函数中使用名称相同的局部变量,
    因为只有声明过该变量的函数才能识别出该变量。局部变量会在函数运行完被删除。
    全局变量 :
    在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。
    全局变量会在页面关闭后被删除。
    向未声明的 JavaScript 变量分配值:
    如果把值赋给尚未声明的变量,该变量将被自动作为 window 的一个属性。不推荐这样使用!!!
    3、JavaScript 注释
    可以添加注释来对 JavaScript 进行解释,或者提高代码的可读性。
    3.1、单行注释以 // 开头。
    单行注释可以阻止其中一条代码行的执行(可用于调试):
    3.2、多行注释以 /* 开始,以 */ 结尾。
    多行注释可用于阻止代码块的执行(可用于调试):
    3.2、@**@ 也是多行注释,但于前面的多行注释不同,前面的多行注释可以根据注释位置折叠,
    而这个多行注释却不可以进行折叠,适用于VS软件
    4、三目运算:条件?true:false
    X=4;If(X>3){“成立”}else{“不成立”}(if…else语句)===X>3 ?“成立”:“不成立”
    4.1、JavaScript 错误 - Throw、Try 和 Catch
    throw 语句创建自定义错误。 try 语句测试代码块的错误。 catch 语句处理错误。
    错误一定会发生:可能是语法错误,通常是程序员个人造成的编码错误或错别字。
    可能是拼写错误或语言中缺少的功能(可能由于浏览器差异)。
    可能是由于来自服务器或用户的错误输出而导致的错误。
    当然,也可能是由于许多其他不可预知的因素。
    JavaScript 测试和捕捉:
    try 语句允许我们定义在执行时进行错误测试的代码块。
    catch 语句允许我们定义当 try 代码块发生错误时,所执行的代码块。
    JavaScript 语句 try 和 catch 是成对出现的。
    语法:try { //在这里运行代码 }catch(err) { //在这里处理错误 }
    在VS的表现形式,控制面板
    控制面板:try{ } catch (Exception){ throw; } 视图:try{ } catch (e){ }
    借鉴于老师上课文档于W3Cchool

    展开全文
  • 成员变量 成员变量的修饰 (1) public 公共变量,可被任何包中的任何类访问,只有在确认任何外部访问都不会带来不良后果的情况下才将成员声明为公共的,公共变量对任何类可见,不具有数据保护功能。 (2)private...

    1. 成员变量

    成员变量的修饰
    在这里插入图片描述
    (1) public 公共变量,可被任何包中的任何类访问,只有在确认任何外部访问都不会带来不良后果的情况下才将成员声明为公共的,公共变量对任何类可见,不具有数据保护功能。
    (2)private私有变量,由 private 修饰的变量称为私有变量,私有变量是不公开的,它们得到了最好的保护,这是对类进行封装时使用的主要方法。
    (3)protected 受保护变量,可以被声明它的类和派生子类以及同一个包中的类访问,而外界无法访问。
    (4)package(default),有 package 修饰的变量常常省略 package 关键字,即没有修饰符的成员被视为包成员。

    static 静态变量, **静态变量是类固有的,可以直接引用,其他成员变量仅仅在被声明、生成实例对象后才存在,**才可以被引用,因此,把静态变量称作类变量、把非静态变量称为实例变量。

    2. 成员方法和参数传递机制

    在Java中,方法只能作为类的成员,故称为成员方法。方法操作类定义的数据,以及提供对数据的访问的代码。

    大多数情况下,程序的其他部分都是通过类的方法和其他类的实例进行交互的,对象的行为由类的方法实现,其他对象可以调用另外一个对象的方法,通过消息(方法参数)的传递实现对该对象行为的控制。

    2.1 成员方法的声明与修饰

    [public] [private] [protected] [package] //访问控制修饰符 ,与成员变量的修饰符有相同作用。

    1. final 最终方法
      当方法被声明为最终方法后,将不能被子类覆盖,即最终方法能被子类继承和使用,但不能在子类中修改或重新定义。
    • 适用于: 保护一些重要的方法不被修改,尤其是那些对类的状态和行为有关键作用的方法被保护后,可以避免未知情况的发生。
    • 注意 : 有时不便于把整个类声明为最终类,这种保护太严格,不利于编程,此时可以有选择的把一些方法声明为最终方法,同样可以起到保护作用。
    1. abstract 方法
      一个抽象类可以含有抽象方法,抽象方法是指没有具体方法体的方法,该方法不能实现,所以抽象方法不能出现在非抽象类中
    • 使用抽象类和抽象方法的原因: 一个抽象类可以定义一个统一的编程接口,使其子类表现出共同的状态和行为,但各自的细节可以不同。子类共有的行为由抽象类中的抽象方法来约束,而子类行为的具体细节则通过抽象方法的覆盖来实现。这种机制可增加编程的灵活性,也是 OOP 继承树的衍生基础。

    例如,直线、圆和矩形等图形对象都有一些共同的位置(位置、边界)和行为(移动、改变大小、画出)。可以利用这些共性,把它们声明为同一个父类的子类,但是一个圆和一个矩形在很多细节方面又是不同的,这时,一个抽象父类是最佳选择。 子类继承父类后,可以通过覆盖方法实现自己的方法。

    1. 方法参数的传值方式
      一个对象和外部交换信息主要靠方法的参数来传递。在 Java中,可传递的参数包括任何数据类型,例如基本数据类型、数组和对象(没错,对象也可以)。
    class MyBox {
    	private int x, y, weight, height;public void draw(Graphics g){
    	g.drawRect(x,y,width,height);
    	}
    }
    

    Java虽然不能传递方法,但可以传递对象,然后调用该对象的方法。

    1. 可变参数
      返回值类型 方法名称(类型 参数名 1 , 类型 参数名 2, 类型…可变参数名){}

    向方法传递可变参数之后,其中可变参数以数组形式保存下来,如果方法中有多个参数,可变参数必须位于最后一项。

    展开全文
  • 单片机全局变量 局部变量

    千次阅读 2018-04-16 20:34:07
    若在C51中定义一个全局变量,编译器将...C51中定义一个的局部变量可以全局变量同名,但在这种情况下,局部变量的优先级较高,而同名的全局变量在该功能模块内暂时被屏蔽。若在C51中定义一个局部变量,编译器会将该...
  • GDB调试指南-变量查看

    千次阅读 2019-03-13 00:01:00
    在启动调试以及设置断点之后,就到了我们非常关键的一步-查看变量。GDB调试最大的目的之一就是走查代码,查看运行结果是否符合预期。既然如此,我们就不得不了解一些查看各种类型变量的方法,以帮助我们进一步定位...
  • 所有变量和函数在使用前必须声明。变量和函数名是标识符。  没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符。变量在声明的时候首先要标明类型,后边可以跟多个变量,之间用逗号隔开。很...
  • JAVA基础一(认识一下Java和Java变量和常量) 目录 一、Java初识 二、Java变量 一、Java初识 1、Java简介: Java是一门高级面向对象开发语言,发布于Sun公司,现已经被Oracle公司收购 2、Java程序执行过程:...
  • Java friend 特性(java中什么是友好变量和友好方法) ...所谓友好即 不被public、protected、private关键修饰的变量和方法 区别在于 比public低一级 用于只能在同一包下访问的变量 不用private、pub...
  • c语言中变量的引用传递指针

    万次阅读 多人点赞 2017-08-02 19:25:15
    掌握了引用型变量和指针,才能深入掌握面向过程的函数调用机制。 引用型变量存储的是变量的地址,指针存储的也是变量的地址,所以本质上来说二者是一样的。 使用引用型变量,子函数中所有的操作会直接修改主函数中的...
  • Shell变量、数据重定向管道

    千次阅读 2016-12-12 15:15:16
    shell中的变量的如何设置读取数据,读取之后如何使用变量?每个程序一般都有输入输出,让我们看看数据重定向如何处理输入输出的?还有,Unix/Linux系统提供丰富的工具,我们如何将这些工具通过管道来组合成...
  • c++内存到底分几个区? 一:  1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据... 3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块
  • 自定义函数 (user-defined function UDF)就是用一个象ABS() 或 CONCAT()这样的固有(内建)...创建删除自定义函数语法: 创建UDF:  CREATE [AGGREGATE] FUNCTION function_name(parameter_name type,[parame...
  • 变量命名规范

    万次阅读 2015-10-25 21:52:40
    变量命名最关键的一点就是:名字要能准确的描述出该变量所代表的事物 变量名长度最好控制在10~16个字符之间 对位于全局命名空间中的名字加以限定词,并且应该一般加在后面 常见的限定词:Total, Sum, Average, Max,...
  • Keil C51中变量和函数的绝对地址定位问题: 1. 变量绝对地址定位  1) 在定义变量时使用 _at_ 关键字加上地址就可.  e.g.  unsigned char idata myvar _at_ 0x40;  把变量 myvar 定义在 idata 的 0x40 处
  • Java允许多线程并发控制,当多个线程同时操作一个可共享资源变量时(如数据的增删改查),将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该...
  •  1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。  2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由os回收 。...
  • Linux下多线程编程互斥锁条件变量的简单使用!
  • MySQL5.6 选项和变量整理

    万次阅读 2013-12-30 14:10:34
    MySQL5.6 选项和变量整理  (2013-04-01 18:10:00) 转载▼ 标签:  mysql5.6配置参数整理 分类: MySQL  --allow-suspicious-udfs 这个选项控制是否用户定义函数只有一个xxx符号用于主函数加载...
  • 如果一个类中存在变量,并且此变量的操作不是原子操作,那么这个类就是非线程安全的类。在线程产生竞争条件的情况下,多线程访问导致原子性不可保证。 常见原子变量: 在java.util.concurrent.atomic包下还有很多类...
  • js设置css自定义变量Introduction 介绍 The basics of using variables 使用变量的基础 Create variables inside any element 在任何元素内创建变量 Variables scope 变量范围 Interacting with a CSS Variable ...
  • 1、全局变量和局部变量 局部变量和全局变量是内存数值操作,属性节点是对控件值的属性进行的操作。理论上,变量的效率比属性节点高。局部变量的作用域是整个VI,它用于在单个VI中传输数据;全局变量的作用域是...
  • 16、nginx 错误页面配置 nginx错误页面包括404 403 500 502 503 504等页面,只需要在server中增加以下配置即可: error_page 404 403 500 502 503 504 /404.html;... 以下将会介绍Nginx的 流量限制 的基础知识高级...
  • Keil C51中变量和函数的绝对地址定位问题: 1. 变量绝对地址定位  1) 在定义变量时使用 _at_ 关键字加上地址就可.  e.g.  unsigned char idata myvar _at_ 0x40;  把变量 myvar 定义在 idata 的 0x4
  • 3、学会如何定义变量,并会使用变量 学习过程: 一、关键字 关键字是程序语言的最小单位,是程序语言事先定义的,并且具有特殊意义的一些标 识符,在有些语言里也称为保留字。正如我们使用人类的语言一样,一篇...
  • C++静态变量、临时变量、性能分析

    千次阅读 2015-05-07 16:12:31
    现在有这个疑问,我有一个功能函数需要频繁调用,这个函数里面的临时变量比较多,我担心这么多的临时变量在这个高频调用的函数里面会影响程序执行的效率,我想将这些局部临时变量改为局部静态变量,不知道这样做能不...
  •  static是C/C++中很常用的修饰符,它被用来控制变量的存储方式可见性。 1.1static的引入  我们知道在函数内部定义的变量,当程序执行到它的定义处时,编译器为它在栈上分配空间,函数在栈上分配的空间在此函数...
  • 多线程-共享全局变量问题

    千次阅读 2019-08-08 18:45:28
    文章目录多线程-共享全局...假设有两个线程t1t2,都要对一个变量g_num进行运算(+1),两个进程t1t2分别对g_num各加10次,g_num的最终结果? import threading import time g_num=0 def work1(num): global g...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 242,904
精华内容 97,161
关键字:

关键变量和控制变量