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

(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. linux下编译qt5.6.0静态库——configure配置(超详细,有每一个模块的说明)(乌合之众)

    linux下编译qt5.6.0静态库 linux下编译qt5.6.0静态库 configure生成makefile 安装选项 Configure选项 第三方库: 附加选项: QNX/Blackberr ...

  2. ubuntu 安装maven提示出错 The program &#39;mvn&#39; can be found in the following packages

    问题: I am trying to install apache maven 3 in Ubuntu 12.04 lts. What I did was open the terminal then ...

  3. Solarized Colorscheme for IntelliJ IDEA

    Solarized Colorscheme for IntelliJ IDEA Original Solarized color scheme developed by Ethan Schoonove ...

  4. 基于visual Studio2013解决面试题之0210树的最远距离

     题目

  5. 经常使用MD5算法代码

    经常使用的MD5算法代码日期: 2014年8月4日作者: 铁锚 MD5,全称为 Message Digest Algorithm 5(消息摘要算法第五版).详情请參考 维基百科:MD5  MD5加密后 ...

  6. Android开发之下载Tomcat服务器的文件到模拟器的SD卡

    Tomcat服务器可以到Apache的官网去下载http://tomcat.apache.org/,如何配置和使用百度下也有很多介绍,只要把Java的SDK配下java_home环境变量就行了,因为T ...

  7. Struts2 Action接收表单参数

    struts2 Action获取表单传值    1.通过属性驱动式    JSP:        <form action="sys/login.action" method ...

  8. 文顶顶 iOS开发UI篇—UITabBarController简单介绍 iOS开发UI篇—UITabBarController简单介绍

    一.简单介绍 UITabBarController和UINavigationController类似,UITabBarController也可以轻松地管理多个控制器,轻松完成控制器之间的切换,典型的例 ...

  9. C 编程最佳实践(书写风格)

    简介本文是为了满足开发人员的需要而写的.我们总结了一套指南,无论作为开发人员还是顾问,这些指南多年来一直都很好地指导着我们,我们把它们作为建议提供给您,希望对您的工作有所帮助.您也许不赞同其中的某些指 ...

  10. android: WheelView组件(滑轮组件)的应用!

    android前段组件中, 填表单,选择条目 的样式有很多, WheelView滚动组件为其中一种,如下图所示:                                          前两 ...