找不到出错原因,让C++码农深感受挫;然而让他们觉得生无可恋的,还是同一段代码,时而出错,时而运行良好。-- 题记 对于初学C++/C的人来说,很容易把static修饰符同const修饰符混淆起来。字面上,一个静态的,一个不变的,意思的确相近。前面讲过const,现在有必要系统地讲解一下static,来做一个区分。 static在C++中有多层意思。最直观的理解是,如果修饰一个变量,则该变量在作用域内,只被定义一次,再定义无效。当然static还有其他涵义。 (一)再定义无效 怎么理解呢?static变量的生命周期,贯穿整个程序的运行,从被定义的地方开始,直到main函数退出为止。同一个静态变量的第二次,第三次乃至第N次定义,都不会导致重新分配内存给变量,也不会修改变量原来的值。看看C++/C入门之堆和栈提到的例子:
第一次打印的值是1,第二次打印的值是2。虽然i是一个局部变量,由于有static修饰,它是被存在内存中的静态区,而不是栈中的,所以不用担心程序退出后被销毁。当第二次调用函数f的时候,编译器碰到static int i=0;的定义,它不会入栈一个新的变量i,而是到静态内存区去找到变量i。 类的静态成员适用同样的规则。
打印出来的i的值分别是1和2。另外,由于类的特殊性,类的成员一般不支持在声明的时候初始化,由static const修饰的int,float/double以及char除外。字符串,数组和结构等,都必须在类外部进行初始化,无论是否有static const或者static修饰。 (二)类的静态函数成员的局限 类的静态函数成员,只能调用类的其他静态函数,以及只能访问类的静态数据成员。它的调用方式可以是 类名::静态函数名 对象名.静态函数名或者对象名->静态函数名 (三)static用来限制变量作用域 如果在函数外定义一个变量,那么这个变量就是全局变量,再在这个变量前加static修饰符,变量的涵义发生了变化,static也不再是静态的意思了。这个时候的变量,变成了一个内部连接,不再为外部可见。static表示内部的意思,正好与extern的意义相反。也就是说,如果在另外一个文件,定义了同名变量,则两个变量没有任何关联(同名变量不能加extern关键字,否则去static变量冲突)。 另外,用extern关键字修饰局部变量也是毫无意义的。 (四)静态(全局)变量的加载顺序是个雷 为什么这么说呢?找不到出错原因,让C++码农深感受挫;然而让他们觉得生无可恋的,还是同一段代码,时而出错,时而运行良好。全局变量的加载顺序,就是一个这样雷。 全局变量定义在一个单一文件当中,它可以被外部文件引用。如果碰巧,两个定义在不同文件中的全局变量互相之间有依赖关系,而不同文件的加载顺序,是编译器不能保证的,我们将会碰到一场灾难。 试看: //First.cpp extern int y; int x = y + 1; //Second.cpp extern int x; int y = x + 1; 如果First.cpp被先加载,x的值为1,y被先初始化为0,当Second.cpp被加载的时候,y的值为2。 相反,如果Second.cpp先被加载,y的值为1,x被初始化为0,当First.cpp被加载的时候,x的值为2。 进入main之后,x和y的初始值,取决于被加载的顺序,而这个顺序,是不能被保证的! 有不少有效的办法,来避免这个情况的出现。最有效的办法还是,避免静态对象依赖的出现。 |
|
来自: 走出尘埃 > 《工控之路——C 学习》