名字的作用域指的是程序可以使用该名字的部分1。
函数中声明的自动变量和参数都是局部变量,其作用域是声明该变量的函数
外部变量指定义在函数之外,可以被多个函数使用的变量。由于C语言不允许在函数中定义其他函数,因此函数本身就是外部的。1 作用域从声明它的地方开始,到其所在的(待编译的)文件的末尾结束。1 (可能有人会说,外部变量不是程序中的所有源文件都可以访问吗?是的,但是这里就要注意作用域的定义,是可以使用的部分,而不是可以访问的部分。在别的文件中如果不声明的话当然不可以使用啦)
外部对象可以被所有源文件引用,若声明为static则对象就只对所在的文件可见,即其他文件到都不能引用,可以达到隐藏外部对象的目的,同时同一个程序不同文件的相同 名字的static对象也不会冲突。 注意:虽然extern可以和定义出现在同一个文件中,但是static和extern不能同时出现在一句声明中,而且一个变量一旦声明为static,同一个文件的其他地方的声明也必须是static static声明的内部变量还是只能在函数内部被使用,但是不管函数是否被调用他都一直存在。1就是说,这个变量可以用来统计该函数被调用了多少次。
变量声明用于说明变量的属性(尤其是变量的类型),而变量定义除此以外还将引起储存器的分配。1 对于外部变量来说,声明有两种:定义性声明和extern声明
如
int sp;这条语句是C (Common) 声明(可能同时也定义)变量, 会为之分配储存单元,到了链接阶段, 1. 如果没在其他模块发现同名(D)符号,即对该变量那得定义,作为未初始化的全局变量, 放在BSS 2. 如果有在其他模块发现同名(D)符号,作为已初始化的全局变量, 放在数据段 所以这条语句可以重复出现在多个源文件中而不会引起重复定义,在一个源文件中出现多次也不会引起错误,因为编译器知道,不管出现多少次,它的值都默认是0,不会冲突。 已验证:
如
extern int sp; extern double val[];当要在外部变量定义之前使用该变量或者外部变量的定义和使用不在同一个源文件中,则必须在相应的变量声明中强制的使用关键字extern1 这条语句是U (Undefined), 声明变量, 到了链接阶段 1. 如果在其他模块有且仅有一个类型(D)的同名符号,将此符号解析到此(D)符号,作为已初始化的全局变量, 放在数据段 2. 如果在其他模块有两个或更多的类型(D)的同名符号,报告“重复定义”,链接失败 3. 如果在其他模块未发现类型(D)的同名符号,但是至少有一个类型(C) 的同名符号, 将此符号解析到此(C)符号上,作为未初始化的全局变量, 放在BSS
其实从作用来看,两者都扩展了变量的作用域,就是提前声明使得它可以提前使用了,但是前者在声明的时候就会分配储存单元,只不过是根据之后有无定义来决定是分配到BBS还是数据段,所以无论如何都会有值;而后者是不会分配储存单元,如果没有找到定义是会报错的。 刚开始我还以为前面一种声明会产生一些逻辑错误,比如说在定义之前使用的话它的值是0,或者编译多个文件的时候如果顺序不同会产生不一样的结果,但其实不会,比如: 那所以为什么要有extern这个关键字呢?或许是为了强制要求这个变量必须在别的地方定义吧,否则编译器悄悄的使用了默认值会产生一些意想不到的问题。有其他看法的小伙伴欢迎评论!
如
int sp = 1;就是D (Data) 定义变量,作为已初始化的全局变量, 放在数据段,如果在一个程序中出现多次会报重复定义的错。
《C程序设计语言》4.4 ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎