1、 函数和全局变量的本文件作用域
1.1 本文件作用域的有效范围
从定义位置开始到文件结束。
a.c
int main(void) //main的本文件作用域:从定义位置到文件末尾 { fun(g_var1, g_var2); return 0; } int g_var1 = 100; //g_var的本文件作用域:从定义位置到文件末尾 int g_var2; int fun(int a) //fun的本文件作用域:从定义位置到文件末尾 { int var; return var +a; }
1.2 通过声明改变本文件作用域
在上面的例子中,如果我们想在main函数中使用g_var1、g_var2、fun的话怎么办?
(1)方法1
挪到main的前面去。
(2)方法2
在main前面进行声明,通过声明将作用域提前。
a.c
int g_var1; int g_var1; int g_var1; int g_var1; int g_var2; int g_var2; int g_var2; int fun(int a); int main(void) { fun(g_var1, g_var2); } int g_var1 = 100; int g_var2; int fun(int a) { int var; return var +a; }
(3)定义与声明的关系
定义与声明的关系,其实就是第1章中介绍的“强弱符号关系”。
我们知道,定义与声明的符号名是相同的,编译时同名符号必须进行统一,然后合并为一个。
在之前,我们详细介绍过强弱符号的统一规则,我们这里再回顾下。
1)谁是强符号,谁是弱符号
· 函数定义:强符号
· 函数声明:弱符号
· 初始化了的全局变量:强符号,我们常将这种称为定义
· 未初始化的全局变量:弱符号,我们常将这种称为声明
2)强弱符号的统一规则
(a)不能允许重复出现同名的强符号,但是允许重复出现有同名的弱符号
· 在a.c中同时定义两个全局变量int a = 100,编译无法通过。
· 在a.c中同时定义两个同名函数fun,也编译无法通过
· 可以对全局变量和函数进行重复声明,因为声明是弱符号,允许同名弱符号重复
以前学C时老师总是讲,声明可以重复,原因就来自于这里。
(b)有一个强符号,其它都是弱符号的话,只保留强符号,其它弱符号消失
同名符号的作用域以最前面的那个符号为准,正是因为这点原因,放在最前面的声明才能提前作用域。
所以声明虽然是弱符号,遇到强符号时消失了,但是它能够提前作用域。
(c)全都是弱符号的话,只留一个即可,其它全部消失
比如a.c中的两个int g_var2都是弱符号,统一符号时只留其中一个,留哪一个由编译器决定。
但是不管留哪一个,作用域范围以最前面的哪一个为准。
同一个.c中的强弱符号统一,是在第二阶段编译时由编译器来完成的,而不同.c中的强弱符号统一,则是由第4阶段“链接”来完成的,这一点我们在第1章详细介绍过,后面介绍“链接域”时,还会再次讲到。
(4)声明全局变量的特殊例子
int g_var1; int main(void) { extern int g_var1; //声明 g_var1 = 100; } int fun(int a) { int var; return var +a; } int g_var1 = 100;
main函数中extern int g_var1这种的生命方式表示,g_var1只在main函数内有效,对后面的fun无效。
extern可以省略吗?
不能省,省了g_var1就变成main的自动局部变量了,extern表示这个全局变量来自于函数外部。
extern有好些用法,不同用法的含义不一样,在这里先了解下这种用法。
假如你只想在main中使用g_var1,不想让g_var1的作用域覆盖到fun函数,就可以使用这种方法,不过这种声明方式用的确实不多,但是在有些源码中可能会看见,这里需要了解下。
同样的,函数也可以进行类似的声明。
int main(void) { extern int fun(int a); //fun的声明。 fun(g_var1, g_var2); } int fun(int a) { int var; return var +a; }
(5)局部变量有声明吗?
局部变量没有声明一说,以下做法时错误的。
int main(void) { int a; //声明:错误用法 a = a + 1; int a = 100; }
说白了就是,对于局部变量来说,变量符号只能有一个,不允许同名符号重复出现。
同一个.c中,变量同名的问题
1)全局变量
(a)如果同名变量都是强符号,这会导致变量重复定义,编译时会报错。
(b)如果同名的是弱符号,它只会改变符号的作用域,除此外没有影响
2)局部变量
不允许存在同名符号。