C程序设计语言--全局/局部变量、头文件、堆栈空间、静态变量
一、全局变量
c语言中变量分为四类,分别是
1.auto 自动变量
2.static 静态存贮分配变量(又分为内部静态和外部静态)
3.extern 全程变量(用于外部变量说明,也就是全局变量)
4.register 寄存器变量(分配在硬件寄存器中)
四大类,所有变量必须先说明(定义),后使用。
下面分别介绍
1.自动变量(局部变量)
局部变量:在一个函数开头或段开头处说明的变量,
它有几个特征,,
a、作用域为定义它的函数
b、编译器不会对自动变量给予隐含的初值,故其值不确定,因此每次使用前必须明确的置初值。
c、形参是自动变量,作用域仅限于相应函数内
d、自动变量随函数的引用而存在和消失,由一次调用到下一次调用之间不保持值。
inti = 0; main( ) { inti = 1; printf(“i=%d, ”, i); { inti = 2; printf(“i=%d, ”, i); { i += 1; printf(“i=%d, ”, i); } printf(“i=%d, ”, i); } printf(“i=%d\n ”, i);}结果:i=1, i=2, i=3, i=3, i=1
1)各种变量在内存的位置
局部变量存储在堆栈中,也就是在栈区内。无论局部变量显示初始化,或者未初始化,都只有当定义它们的程序块被调用时(即执行时),才分配空间,声明或定义时并不分配,局部变量不是可执行模块的一部分!!除非显示地对局部变量进行初始化,否则,它们的初始值是不确定的。全局变量没有声明在任何一个函数内,作用范围在程序运行始终存在。能被同一源文件的任何函数使用,也能被其他文件中的函数使用,但要使用extern关键字(这里再重复一遍,前边已经说明了一次)。全局变量存储在数据段中。全局变量显示初始化时(如b),或者未初始化时(如a),在程序映像中有不同的分区:已初始化的全局变量是可执行模块的一部分。未初始化的全局变量则不是可执行模块的一部分,只有当定义它们的程序被调用时(即执行时),才分配空间,声明或定义时并不分配。未初始化的全局变量在运行时被初始化为0。静态变量,用static关键字定义的变量,与局部变量相比, static局部变量有三点不同,存储空间分配不同,auto类型分配在栈上,属于动态存储类别,占动态存储区空间,函数调用结束后自动释放, 而static分配在静态存储区,在程序整个运行期间都不释放,两者之间的作用域相同,但生存期不同;static局部变量在所处模块在初次运行时进行初始化工作,且只操作一次;静态全局变量用来表示不能被其它文件访问的全局变量和函数。为了限制全局变量/函数的作用域,函数或变量前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。注意:对于外部(全局)变量,不论是否有static限制,它的存储区域都是在静态存储区,生存期都是全局的。此时的static只是起作用域限制作用,限定作用域在本模块(文件)内部。静态全局变量与全局变量的差别是:静态全局变量只能被同一源文件中的函数调用,其他文件中的函数不能调用静态全局变量。二、头文件的规范使用
为了头文件不被重复引用,在头文件的开始需要使用一定的规范约束。多重包含在绝大多数情况下出现在大型程序中,它往往需要使用很多头文件,因此要发现重复包含并不容易。要解决这个问题,我们可以使用条件编译。如果所有的头文件都像下面这样编写:
#ifndef _HEADERNAME_H
#define _HEADERNAME_H
...
#endif
那么多重包含的危险就被消除了。当头文件第一次被包含时,它被正常处理,符号_HEADERNAME_H被定义为1。如果头文件被再次包含,通过条件编译,它的内容被忽略。符号_HEADERNAME_H按照被包含头文件的文件名进行取名,以避免由于其他头文件使用相同的符号而引起的冲突。
但是,你必须记住预处理器仍将整个头文件读入,即使这个头文件所有内容将被忽略。由于这种处理将托慢编译速度,所以如果可能,应该避免出现多重包含。
...
#endif
这是宏定义的一种,它可以根据是否已经定义了一个变量来进行分支选择,一般用于调试等等.实际上确切的说这应该是预处理功能中三种(宏定义,文件包含和条件编译)中的一种----条件编译。 C语言在对程序进行编译时,会先根据预处理命令进行“预处理”。C语言编译系统包括预处理,编译和链接等部分。
#ifndef x
//先测试x是否被宏定义过
#define x
//如果没有宏定义下面就宏定义x并编译下面的语句
...
#endif
//如果已经定义了则编译#endif后面的语句
条件指示符#ifndef检查预编译常量在前面是否已经被宏定义。如果在前面没有被宏定义,则条件指示符的值为真,于是从#ifndef到#endif之间的所有语句都被包含进来进行编译处理。相反,如果#ifndef指示符的值为假,则它与#endif指示符之间的行将被忽略。条件指示符#ifndef 的最主要目的是防止头文件的重复包含和编译。
头文件中的#ifndef
千万不要忽略了头件的中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。
还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:
#ifndef <标识>
#define <标识>
......
......
#endif
<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h
#ifndef _STDIO_H_
#define _STDIO_H_
......
#endif