只能被初始化一次的static变量???

本文深入解析C++中静态变量的工作机制,包括静态变量的初始化原理、如何通过内存位来标记初始化状态,以及静态变量在类中的特殊性质。通过代码示例,清晰展示静态变量只初始化一次的特点,并解释了为何会如此。同时,提供了实验方法验证静态变量的初始化行为。

static全局变量是限定作用域的全局变量

     static函数只能被本文件里的内容使用(相当于私有函数),是限定作用域的全局函数。
     C++里头的static函数是相对成员函数而言,其调用对象是类,而不是对象
     C++在类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝; 
     C++在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的static 成员变量。

童鞋们在学习C++的时候,往往只是按照书本上的原文去强行记忆各种特性,比方说,静态变量只初始化一次。你心中一定在默念:一定要记住,static只会初始化一次云云,希望自己能够记住。告诉你,你为什么总是记不住,因为你没有正真理解静态变量的原理, 所以下面我就来告诉大家它的原理,直接上代码:

[code=C/C++]
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
      int initNum = 3;
      for (int i=5; i > 0; --i)
     {
            static int n1 = initNum;
            n1++;
            printf("%d\n", n1);
     }
     getchar();
     return 0;
}
[/code]
输出结果:
4
5
6
7
8
在这里我们可以看到虽然代码循环了5次,静态变量n1确实只初始化了一次。那么为什么呢?继续上代码,相信大家就会明白些许了。
[code=C/C++]
int _tmain(int argc, _TCHAR* argv[])
{
      int initNum = 3;
      for (int i=5; i > 0; --i)
      {
              static int n1 = initNum;
              //我们在这里增加了两句代码,把n1所指的内存地址后面4个字节赋值成0
              int* p = &n1;
              p++;
              *p = 0;

               //end

               n1++;

               printf("%d\n", n1);
        }
        getchar();
        return 0;
}
[/code]
输出结果:
4
4
4
4
4
这次,静态变量居然跟随着5次循环也初始化了5次。你一定非常诧异,其实我们不难推断,其实静态变量就是通过静态变量后面的一个32位内存位来做记录,以标识这个静态变量是否已经初始化。而我们的p++;*p = 0;却每次都将这个值赋值为0,所以程序就一直认为n1一直没有被初始化过,并每次都初始化一次。看一下内存,就更明了了:
0x00E8716C  03 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 b0 e7 1e 6a 00 00 00
这里的内存地址就是静态变量n1的地址,值是3,后面还有一个1,你看到了吗,这个就是程序用来记录该静态变量是否初始化的标识位啦。现在你一定明白原理了,并且能轻松记住静态变量的特性了吧?
童鞋们还可以试一下,多个静态变量时,标识位的表示形式,以深入学习(透露一下,每一位标识一个静态变量的初始化状态)。
以上代码有一点需要说明:代码中之所以要用int initNum = 3;而不是直接用static int n1 = 3;是因为如果给静态变量直接赋值一个常量的话,编译器会进行优化,导致程序在一启动时,就初始化好了,不便于我们观察静态变量内存上的改变。
<think>嗯,用户想了解C语言中全局变量初始化次数和规则,以及相关的标准。首先,我需要回忆一下C语言的标准,特别是C99和C11的相关内容。根据之前的引用资料,C99规定全局变量static变量必须用常量表达式初始化,不能是非常量。而C++允许,但C不行。这可能涉及到存储区的不同,比如.data和.bss段。 然后,用户提到的初始化次数应该是指全局变量在程序运行期间是否会被多次初始化。一般来说,全局变量在程序启动时初始化一次,之后不会再初始化。不过需要确认是否有特殊情况,比如动态库加载或者多线程环境,但C标准可能不涉及这些,可能更多是编译器实现的问题。 接下来,关于初始化的规则,需要明确静态存储期的变量(全局和静态变量)的初始化时机和方式。根据引用3,C语言要求在编译时确定全局变量的初始值,所以必须使用常量。而C++的处理方式不同,允许运行时初始化,但C不行。这可能导致在C中如果尝试用变量初始化全局变量会报错,比如int i=5; int j=i; 这样的代码在C中是不允许的,但在C++中可以。 另外,未初始化的全局变量会被默认初始化为0,存储在.bss段。这部分可能在程序启动时由运行时系统清零。而显式初始化的非零全局变量则存储在.data段。 关于初始化次数,标准应该规定全局变量初始化一次,在程序启动时完成。对于静态变量也是如此,函数内的静态变量初始化一次,在第一次执行到定义处时初始化。 现在需要整理这些点,分步骤解释给用户。同时要引用提供的参考资料,特别是引用1、3中提到C99的标准和C++的区别,以及初始化时的存储区分配问题。 可能还需要提到,在C语言中,全局变量初始化必须在编译时确定,因此不能使用非常量表达式,而局部静态变量同样适用这一规则。此外,野指针的问题,如果全局指针变量没有显式初始化,会被初始化为NULL,避免成为野指针,这也是C语言的规定。 总结回答的结构应该是:先总述C语言全局变量初始化规则,然后分点详细说明初始化的次数、标准规定、与C++的区别、存储区的影响,以及未初始化的处理方式。最后生成相关问题,帮助用户进一步理解。</think>关于C语言全局变量初始化行为,其规则和标准可总结如下: ### 一、全局变量初始化规则 1. **初始化次数** - 全局变量在程序启动时**仅初始化一次**,其生命周期持续到程序结束[^1][^3]。 - 若未显式初始化,系统会将其默认初始化为零值(如指针为`NULL`,数值为0)[^1][^3]。 2. **初始化表达式限制** - 必须使用**编译时可确定的常量表达式**,例如`int a = 10 + 5;`。 - 禁止使用运行时才能确定值的表达式,例如`int b = func();`或`int c = non_const_var;`。 3. **存储区划分** - 显式初始化的全局变量存储在`.data`段。 - 未初始化的全局变量存储在`.bss`段(由系统自动清零)。 ### 二、与C++的关键差异 ```c // C语言会报错,C++允许 int i = 5; int j = i; // 错误:initializer element is not constant(C语言) ``` - C++通过添加**隐式初始化代码**在`main()`前完成赋值,而C语言要求严格编译期初始化[^3]。 ### 三、野指针问题规避 全局指针变量若未显式初始化,会被自动设为`NULL`,避免成为野指针: ```c int *p; // 等价于 int *p = NULL; ``` ### 四、标准文档依据 - **C99标准**:明确要求全局/静态变量初始化表达式必须是常量(C11沿用此规则)[^1]。 - **代码示例分析**: ```c const int k = 5; int m = k; // 合法:k是常量 int n = rand(); // 非法:运行时函数调用 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值