您的位置:首页 > 编程语言 > C语言/C++

C语言——符号的声明与定义

2015-11-18 10:50 387 查看
C语言之所以博大精深,是因为想要真正理解它,就要理解它背后故事。我们知道从源代码到可执行文件的过程分四步:预编译,编译,汇编,链接,而其中核心在于编译(预编译是相对简单的文本操作,汇编是一个相对简单的映射,链接是符号在地址空间中的最终定位)。编译是以文件为单元进行的(每个经过预处理之后的文件都是单独编译,生成一个.o文件)。编译的过程就是编译器理解C的过程,也是C在语言层面上的灵魂所在。本文主要说明符号(idendifier)的声明(declaration)与定义(definition)是怎么回事。

先来个例子吧,比如有这么一个文件func.c:

int var_global;
extern int var_extern;

int func()
{
int add(int arg1, int arg2);
int var_local;
var_global = 100;
var_local = add(var_global, var_extern);

return var_local;
}


这里出现了五个符号:var_global,var_extern,func,add和var_local。编译器需要知道这些符号在哪些地方是有意义的(比如这里的var_local在func外面没有意义)以及它们有什么意义,然后决定要不要针对这些符号做些什么(比如分配空间,怎么初始化这些空间等等)。

“int var_global;”告诉编译器:var_global是一个int型的变量,需要给它在全局变量区分配空间并初始化为0,它的合法范围是当前文件(在当前文件后面再遇到var_global的时候就可以用它了)。所以我们说:这里声明并且定义了一个全局变量var_global。

“extern int var_extern;”告诉编译器:var_extern是一个int型的变量,不要给它分配空间(它的空间一定已经在别的地方分配好了),它的合法范围是当前文件。所以我们说:这里声明了一个全局变量var_extern。

“int func() {...}”告诉编译器:func是一个参数为空并且返回int的函数,而且后面跟了函数体的具体定义,需要编译成最终的指令(为它在全局代码区分配一个空间来装编译它得到的指令),它的合法范围是当前文件。所以我们说:这里声明并定义了一个函数func。

“int add(int arg1, int arg2);”告诉编译器:add是一个参数为(int,int)并且返回int的函数,没有跟函数的定义,合法范围是当前函数体(即func内)。所以我们说:这里声明了一个函数add。

“int var_local;”告诉编译器:var_local是一个int型的变量,需要在栈上给它分配空间,不用对它初始化,它的合法范围是当前函数体。所以我们说:这里声明并定义了一个局部变量var_local。

“var_global = 100;”即不是声明也不是定义,而是对已经声明了的符号(var_global)的使用。由于前面我们通过“int var_global;”声明了var_global,编译器就已经知道足够的信息来使用它了。同理,“var_local = add(var_global, var_extern);”和“return var_local;”也是对已经声明了的var_local,var_extern和add的使用。编译器知道var_local是一个int变量,var_extern是一个int变量,add是一个接受两个int并且返回一个int的函数,这些信息足够编译器正确地编译。至于这几个符号是在哪里定义的,在编译这三个语句的时候编译器并不关心。

所以,对于文件中所有出现的符号,编译器都已经知道了足够的信息,因而单独编译这个文件是可以通过的(如果没有任何一个地方提供对var_extern和add的定义,则链接步骤会出问题)。我们可以在其它代码里使用func,比如在main.c中:

#include <stdio.h>

int var_extern = 1000;

int func();

int add(int arg1, int arg2)
{
return arg1 + arg2;
}

main()
{
int var = func();
printf("value is: %d\n", var);
}


“#include <stdio.h>”引用了stdio.h的内容,里面有对下文中用到的printf的声明。

“int var_extern = 1000;”声明并定义了var_extern,并且初始化其为1000。
“int func();”声明了func,这个函数的定义在别处(在func.c中)。
“int add(int arg1, int arg2) {...}”声明并定义了add。

那么编译这两个文件生成的可执行文件执行起来就会打出:“value is: 1100”。

所以,通俗地讲:“声明就是帮助编译器理解和使用一个符号,定义就是给这个符号分配了东西”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言