一、局部变量和全局变量:

(1)局部变量:局部变量也叫自动变量,它声明在函数开始,生存于栈,它的生命随着函数的返回而结束。

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. auto int i = 9; <span style="white-space:pre">  </span>//声明局部变量的关键字是 auto; 因可以省略,所以几乎没人使用
  5. printf("%d\n", i);
  6. getchar();
  7. return 0;
  8. }
#include <stdio.h>

int main(void)
{
auto int i = 9; //声明局部变量的关键字是 auto; 因可以省略,所以几乎没人使用 printf("%d\n", i);
getchar();
return 0;
}

(2)全局变量:全局变量声明在函数体外,一般应在函数前。每个函数都可以使用它,不过全局变量应尽量少用。

  1. #include <stdio.h>
  2. void add(void);
  3. void mul(void);
  4. int gi = 3; <span style="white-space:pre">      </span>//全局变量(声明在函数外)
  5. int main(void)
  6. {
  7. printf("%d\n", gi); //输出的是 3
  8. add();
  9. printf("%d\n", gi); //输出的是 5
  10. mul();
  11. printf("%d\n", gi); //输出的是 10
  12. getchar();
  13. return 0;
  14. }
  15. void add(void) {
  16. gi += 2;
  17. }
  18. void mul(void) {
  19. gi *= 2;
  20. }
#include <stdio.h>

void add(void);
void mul(void); int gi = 3; //全局变量(声明在函数外) int main(void)
{
printf("%d\n", gi); //输出的是 3 add();
printf("%d\n", gi); //输出的是 5 mul();
printf("%d\n", gi); //输出的是 10 getchar();
return 0;
} void add(void) {
gi += 2;
} void mul(void) {
gi *= 2;
}

全局变量会被初始化为空, 而局部变量在没有赋值前是一个垃圾值:

  1. #include <stdio.h>
  2. int gi;<span style="white-space:pre">           </span>//全局变量
  3. int main(void)
  4. {
  5. int i;<span style="white-space:pre">        </span>//局部变量
  6. printf("%d, %d\n", gi, i);
  7. getchar();
  8. return 0;
  9. }
#include <stdio.h>

int gi;			//全局变量

int main(void)
{
int i; //局部变量 printf("%d, %d\n", gi, i); getchar();
return 0;
}

当全局变量与局部变量重名时,使用的是局部变量:

  1. #include <stdio.h>
  2. int a = 111, b = 222;
  3. int main(void)
  4. {
  5. int a = 123;
  6. printf("%d,%d\n", a, b);<span style="white-space:pre">  </span>//输出的是 123,222
  7. getchar();
  8. return 0;
  9. }
#include <stdio.h>

int a = 111, b = 222;

int main(void)
{
int a = 123;
printf("%d,%d\n", a, b); //输出的是 123,222 getchar();
return 0;
}

二、对象的生存周期(lifetime)

(1)静态生存周期(即全局变量的生存周期)

具有静态生存周期的所有对象,都是在程序开始执行之前就被事先创建和初始化。它们的寿命覆盖整个程序的执行过程。如在函数内定义了一个static变量,那第一次调用该函数后,该变量的值将会被保留,当第二次被调用时,该变量的值还是第一次调用结束时的值。

(2)自动生存周期(即局部变量的生存周期)

自动生存周期的对象的寿命由“对象定义所处在的大括号{}”决定。每次程序执行流进入一个语句块,此语句块自动生存周期的对象就会被创建一个新实例,同时被初始化。

三、标识符的链接(linkage)

(1)外部链接

表示在整个程序中(多个程序文件)是相同的函数或对象。常见的有,在函数体外声明的extern变量。

(2)内部链接

表示只在当前程序文件中是相同的函数或对象。其它程序文件不能对其进行访问。常见的有,在函数体外声明的static变量。

(3)无链接

一般声明在函数内部的auto、register变量、还有函数的参数,都是无链接。它的作用域是函数内部。

四、存储类型修饰符总结:

存储类型修饰符可以修改标识符的链接和对应对象的生存周期;标识符有链接,而非生命周期;对象有生存周期,而非链接;函数标识符只可用static、extern修饰,函数参数只可用register修饰。

(1)auto(对应自动生存周期)

auto修饰符只能用在函数内的对象声明中,即仅在语句块内使用。

声明中有auto修饰符的对象具有自动生存周期。

它们仅存在于被定义的当前执行代码块中,即局部变量在进入模块时生成,在退出模块时消亡。

定义局部变量的最常见的代码块是函数。 语言中包括了关键字auto,它可用于定义局部变量。但自从所有的非全局变量的缺省值假定为auto以来,auto就几乎很少使用了。

(2)static(对应静态生存周期)

如果是定义在函数外,那么该对象具有内部链接,其它程序文件不能对其访问。如果是定义在函数内,那么该对象具有无链接,函数外不能对其访问。

(注意:static变量初始化时,只能用常量)

用 static 关键字修饰的局部变量称为静态局部变量。

静态局部变量存值如同全局变量,区别在于它只属于拥有它的函数,它也和全局变量一样会被初始化为空。

  1. #include <stdio.h>
  2. void fun1(void);
  3. void fun2(void);
  4. int main(void)
  5. {
  6. int i;
  7. for (i = 0; i < 10; i++) fun1();
  8. printf("---\n");
  9. for (i = 0; i < 10; i++) fun2();
  10. getchar();
  11. return 0;
  12. }
  13. void fun1(void) {
  14. int n = 0;<span style="white-space:pre">            </span>//一般的局部变量
  15. printf("%d\n", n++);
  16. }
  17. void fun2(void) {
  18. static int n;<span style="white-space:pre">     </span>//静态局部变量,会被初始化为空
  19. printf("%d\n", n++);
  20. }
#include <stdio.h>

void fun1(void);
void fun2(void); int main(void)
{
int i; for (i = 0; i < 10; i++) fun1();
printf("---\n");
for (i = 0; i < 10; i++) fun2(); getchar();
return 0;
} void fun1(void) {
int n = 0; //一般的局部变量
printf("%d\n", n++);
} void fun2(void) {
static int n; //静态局部变量,会被初始化为空
printf("%d\n", n++);
}

用 static 关键字修饰的全局变量是静态全局变量,静态全局变量只能用于定义它的单元。

  1. //譬如在 File1.c 里面定义了:
  2. static int num = 99;  /* 去掉前面的 static 其他单元才可以使用 */
  3. //在 File2.c 里使用:
  4. #include <stdio.h>
  5. extern int num;
  6. int main(void)
  7. {
  8. printf("%d\n", num);
  9. getchar();
  10. return 0;
  11. }
//譬如在 File1.c 里面定义了:
static int num = 99; /* 去掉前面的 static 其他单元才可以使用 */ //在 File2.c 里使用:
#include <stdio.h> extern int num; int main(void)
{
printf("%d\n", num); getchar();
return 0;
}

用静态变量记录函数被调用的次数:

  1. #include <stdio.h>
  2. int fun(void);
  3. int main(void)
  4. {
  5. int i;
  6. for (i = 0; i < 10; i++) {
  7. printf("函数被调用了 %2d 次;\n", fun());
  8. }
  9. getchar();
  10. return 0;
  11. }
  12. int fun(void) {
  13. static int n;
  14. return ++n;
  15. }
#include <stdio.h>

int fun(void);

int main(void)
{
int i;
for (i = 0; i < 10; i++) {
printf("函数被调用了 %2d 次;\n", fun());
}
getchar();
return 0;
} int fun(void) {
static int n;
return ++n;
}

(3)const

(4)extern(对应静态生存周期)

extern 意为“外来的”。它的作用在于告诉编译器:这个变量或者函数的定义在别的地方,当遇到此变量或函数时应到其他模块中寻找其定义。

(PS:这个变量,它可能不存在于当前的文件中,但它肯定要存在于工程中的某一个源文件中或者一个Dll的输出中。)

  1. #include <stdio.h>
  2. extern int g1;
  3. int main(void)
  4. {
  5. extern int g2;<span style="white-space:pre">    </span>//告诉编译器g2定义在其他地方
  6. printf("%d,%d\n", g1,g2);
  7. getchar();
  8. return 0;
  9. }
  10. int g1 = 77;
  11. int g2 = 88;
#include <stdio.h>

extern int g1;

int main(void)
{
extern int g2; //告诉编译器g2定义在其他地方 printf("%d,%d\n", g1,g2);
getchar();
return 0;
} int g1 = 77;
int g2 = 88;

使用extern时,注意不能重复定义,否则编译报错,如:

程序文件一:

  1. extern int a = 10; <span style="white-space:pre">   </span>//编译警告,extern的变量最好不要初始化
extern int a = 10; 	//编译警告,extern的变量最好不要初始化 

程序文件二:

  1. extern int a = 20; <span style="white-space:pre">   </span>//重复定义,应改为extern int a;
extern int a = 20; 	//重复定义,应改为extern int a; 

(一般最好这样,如果需要初始化,可把extern修饰符去掉(但也不要重复定义),另外如果其它程序文件也需要用到该变量,可用extern来声明该变量。这样会比较清晰。)

另外,extern也可用来进行链接指定。

(5)volatile

(6)register(即寄存器变量,对应自动生存周期)

当声明对象有自动生存周期时,可以使用register修饰符。因此,register也只能用在函数内的声明中。

register修饰符暗示编译程序相应的变量将被频繁地使用,如果可能的话,应将其保存在CPU的寄存器中(而不是栈或堆),以加快其存储速度。然而,编译器不见得会这么做,因此效果一般般。了解一下就行,不建议使用。

  1. #include <stdio.h>
  2. #include <time.h>
  3. #define TIME 1000000000
  4. int m, n = TIME;<span style="white-space:pre">      </span>//全局变量
  5. int main(void)
  6. {
  7. time_t start, stop;
  8. register int a, b = TIME;<span style="white-space:pre"> </span>//寄存器变量
  9. int x, y = TIME;<span style="white-space:pre">      </span>//一般变量
  10. time(&start);
  11. for (a = 0; a < b; a++);
  12. time(&stop);
  13. printf("寄存器变量用时: %d 秒\n", stop - start);
  14. time(&start);
  15. for (x = 0; x < y; x++);
  16. time(&stop);
  17. printf("一般变量用时: %d 秒\n", stop - start);
  18. time(&start);
  19. for (m = 0; m < n; m++);
  20. time(&stop);
  21. printf("全局变量用时: %d 秒\n", stop - start);
  22. getchar();
  23. return 0;
  24. }
#include <stdio.h>
#include <time.h> #define TIME 1000000000 int m, n = TIME; //全局变量 int main(void)
{
time_t start, stop; register int a, b = TIME; //寄存器变量
int x, y = TIME; //一般变量 time(&start);
for (a = 0; a < b; a++);
time(&stop);
printf("寄存器变量用时: %d 秒\n", stop - start); time(&start);
for (x = 0; x < y; x++);
time(&stop);
printf("一般变量用时: %d 秒\n", stop - start); time(&start);
for (m = 0; m < n; m++);
time(&stop);
printf("全局变量用时: %d 秒\n", stop - start); getchar();
return 0;
}

使用register修饰符有几点限制:

 

  首先,register变量必须是能被CPU所接受的类型。这通常意味着register变量必须是一个单个的值,并且长度应该小于或者等于整型的长度。不过,有些机器的寄存器也能存放浮点数。

 

  其次,因为register变量有可能被存放到寄存器中而不是内存中,所以不能用“&”来获取register变量的地址。

 

  总的来说,由于寄存器的数量有限,而且某些寄存器只能接受特定类型的数据(如指针和浮点数),因此真正起作用的register修饰符的数目和类型都依赖于运行程序的机器,而任何多余的register修饰符都将被编译程序所忽略。

 

  在某些情况下,把变量保存在寄存器中反而会降低程序的运行速度。因为被占用的寄存器不能再用于其它目的;或者变量被使用的次数不够多,不足以装入和存储变量所带来的额外开销。

 

  早期的C编译程序不会把变量保存在寄存器中,除非你命令它这样做,这时register修饰符是C语言的一种很有价值的补充。然而,随着编译程序设计技术的进步,在决定那些变量应该被存到寄存器中时,现在的C编译环境能比程序员做出更好的决定。实际上,许多编译程序都会忽略register修饰符,因为尽管它完全合法,但它仅仅是暗示而不是命令。

(7)缺省修饰符

函数内,与auto相同,函数外,与extern相同。

五、概括性例子:

  1. int func1(void); <span style="white-space:pre"> </span>//func1具有外部链接
  2. int a = 10; <span style="white-space:pre">      </span>//a具有外部链接,静态生存周期
  3. extern int b = 1; <span style="white-space:pre">    </span>//b具有外部链接,静态生存周期。但编译会有警告extern变量不应初始化,同时也要注意是否会重复定义
  4. static int c; <span style="white-space:pre">        </span>//c具有内部链接,静态生存周期
  5. static int e; <span style="white-space:pre">        </span>//e具有内部链接,静态生存周期
  6. static void func2(int d)
  7. {
  8. <span style="white-space:pre">  </span>//func2具有内部链接;参数d具有无链接,自动生存周期
  9. <span style="white-space:pre">  </span>extern int a; <span style="white-space:pre"> </span>//a与上面的a一样(同一变量),具有外部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明
  10. <span style="white-space:pre">  </span>int b = 2; <span style="white-space:pre">    </span>//b具有无链接,自动生存同期。并且将上面声明的b隐藏起来
  11. <span style="white-space:pre">  </span>extern int c; <span style="white-space:pre"> </span>//c与上面的c一样,维持内部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明
  12. <span style="white-space:pre">  </span>//如果去掉了extern修饰符,就跟b类似了,无链接,自动生存周期,把上面声明的c隐藏起来
  13. <span style="white-space:pre">  </span>static int e; <span style="white-space:pre"> </span>//e具有无链接,静态生存周期。并且将上面声明的e隐藏起来;初始化值为0
  14. <span style="white-space:pre">  </span>static int f; <span style="white-space:pre"> </span>//f具有无链接,静态生存周期
  15. }
int func1(void); 	//func1具有外部链接
int a = 10; //a具有外部链接,静态生存周期
extern int b = 1; //b具有外部链接,静态生存周期。但编译会有警告extern变量不应初始化,同时也要注意是否会重复定义
static int c; //c具有内部链接,静态生存周期
static int e; //e具有内部链接,静态生存周期
static void func2(int d)
{
//func2具有内部链接;参数d具有无链接,自动生存周期
extern int a; //a与上面的a一样(同一变量),具有外部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明
int b = 2; //b具有无链接,自动生存同期。并且将上面声明的b隐藏起来
extern int c; //c与上面的c一样,维持内部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明
//如果去掉了extern修饰符,就跟b类似了,无链接,自动生存周期,把上面声明的c隐藏起来
static int e; //e具有无链接,静态生存周期。并且将上面声明的e隐藏起来;初始化值为0
static int f; //f具有无链接,静态生存周期
}

相关链接参考:

http://developer.51cto.com/art/201105/261465.htm

http://apps.hi.baidu.com/share/detail/30353645

http://www.cnblogs.com/del/archive/2008/12/04/1347305.html

c++各类变量汇总的更多相关文章

  1. 帝国cms支持的变量及灵动标签变量汇总

    帝国CMS对首页.列表页.内容页这三个页面模板支持的变量是不同的,有的是通用的,有的不是通用的,本文就这三个模板常用的变量列于此,另外灵动标签很好用啊,也顺便收藏于此,以备后用,到时不用到处翻来翻去的 ...

  2. ubuntu下各类快捷键汇总记录

    一.环境 Ubuntu 16.04 二.快捷键汇总如下 2.1 将图形界面下的terminal最大化:ctrl+super+向上的方向键 2.2 将图形界面下的terminal最小化:ctrl+sup ...

  3. Tasker, Android系统增强神器, 变量汇总

    http://tasker.dinglisch.net/userguide_summary.html#variables.html http://tasker.dinglisch.net/usergu ...

  4. mac .bash_profile环境变量汇总

    export CATALINA_HOME=/Applications/MyApplications/apache-tomcat-7.0.54 export PATH=$PATH:$CATALINA_H ...

  5. 每日扫盲:eclipse快捷键 包括查找类、方法、变量汇总

    [Ct rl+T] 搜索当前接口的实现类 1. [ALT +/]    此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类.方法和属性的名字时,多体验一下[ ...

  6. Java的类成员变量、实例变量、类变量,成员方法、实例方法、类方法

    总是被这些相似的概念搞晕,查阅了资料后做个小总结,以变量为例,方法辨析类似. 1.多胞胎名字汇总辨析 成员变量和成员方法是范围最大的定义,提到成员变量就可以理解成你所定义在一个类体中的各类变量的统称, ...

  7. C变量类型和作用域

    C语言中所有变量都有自己的作用域,申明变量的类型不同,其作用域也不同.C语言中的变量,按照作用域的范围可分为两种, 即局部变量和全局变量. 一.局部变量 局部变量也称为内部变量.局部变量是在函数内作定 ...

  8. 嵌入式调试器原理和各类调试器集锦(JLINK、STLINK、CCDEBUG)

    工欲善其事,必先善其器.调试器在嵌入式开发调试中的重要性不言而喻,单步.断点和监察的效率远高于串口打印.但是,调试器对于一般开发人员往往是一个黑匣子.今天我们就来谈谈调试器的原理,顺便把自己的几类调试 ...

  9. Linux后台开发面试问题汇总

    个人从事安全后台开发,当然是linux环境下的了.举几个常见的问题.1. 数据结构基础.比如实现一个最简单的哈希表.2. 操作系统基础.linux进程模型,堆/栈的区别,大概的位置,各往哪个方向生长, ...

随机推荐

  1. cocos2d-x 新建项目 Cannot open include file: ‘cocos2d.h’

    新建cocos2d-x 项目分这么几步. 1. 下载最新的cocos2d-x 2. 安装 vs2010 3. 解压cocos2d-x 压缩包,并双击"install-templates-ms ...

  2. poj 百练 2765 八进制小数(精度问题)

    2765:八进制小数 查看 提交 统计 提示 提问 总时间限制:  1000ms  内存限制:  65536kB 描写叙述 八进制小数能够用十进制小数精确的表示.比方,八进制里面的0.75等于十进制里 ...

  3. [Warning] Aborted connection 11203 to db: 'ide' user: 'nuc' host: 'prd01.mb.com' (Got an error writi

    PS:一台物理机扯分了3个虚拟机,一个主db,一个主备,一个从备. 切换到0301的时候 Sep  6 09:16:16 prddb0301 mysqld: 130906  9:16:16 [Warn ...

  4. 解决php下多人同时操作数据表

    当同一时刻,多人对同一个表进行insert或者update的时候,往往会出现同一条数据出现好多次或者一些奇怪的问题,可以通过mysql的锁表机制来进行排队解决这个问题 php中插入数据之前锁表 // ...

  5. ALV 数值列负号前置 (EDIT_MASK应用)

    1.建立自定义函数 浮点数显示FUNCTION conversion_exit_zsign_output.*"---------------------------------------- ...

  6. WinSock - 建立无连接的通信

    1.建立一个基于对话框的工程,并在第二步中选择WOSA支持 2.建立客户端 (1)在头文件中添加成员变量 public: CSocket m_clientsocket; (2)每隔一秒钟向服务端发送一 ...

  7. JavaScript常用全局属性与方法

    最近,在学习JavaScript,Java作域链包含全局,记录下常用的全局属性与方法,就当是知识的积累,未列出全部,如需查看全部可参考JS相关的API文档. 常用的全局属性:  全局属性      作 ...

  8. UVA 565 565 Pizza Anyone? (深搜 +位运算)

      Pizza Anyone?  You are responsible for ordering a large pizza for you and your friends. Each of th ...

  9. Delphi中使用python脚本读取Excel数据

    Delphi中使用python脚本读取Excel数据2007-10-18 17:28:22标签:Delphi Excel python原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 . ...

  10. redis 获取key 过期时间

    <pre name="code" class="html">127.0.0.1:6379> keys *b4f107c6-e96c-4a1e- ...