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

原创 2015年11月18日 10:50:56

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”。


所以,通俗地讲:“声明就是帮助编译器理解和使用一个符号,定义就是给这个符号分配了东西”。


版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/tsx851。

C语言中声明和定义的区别——分析extern关键词。

一直很迷惑C语言中的声明和定义的有些实践中的用法,说迷惑实践是因为声明和定义的概念上的区别是很明确的。 定义和声明的区别(主要针对变量): 定义是要为变量分配存储空间,还可以在定义的时候为变量指定...

C语言变量声明问题——变量定义一定要放在所有执行语句/语句块的最前面吗?

参考网址:http://www.cnblogs.com/web-HCJ/p/4468689.html 报错信息:error C2065: 'salary' : undeclared ...

<C语言漫谈录>3——关键字,变量定义和声明

———————————————————————————————————————————————— 前言:关于C语言的书,那是数不胜数,其中不乏佳作。我在这里并不打算从头开始讲解C语言,因为那种书籍实...

keil 中——C语言模块化编程时全局变量、结构体的定义、声明以及头文件包含的处理方法

详解keil采用C语言模块化编程时全局变量、结构体的定义、声明以及头文件包含的处理方法!            以前写单片机程序时总是把所用函数和变量都写在一个c文件里,后来遇到大点的项目,程序动则...
  • Cowena
  • Cowena
  • 2015年11月09日 09:02
  • 2649

C语言——定义&&声明

1.变量的定义&声明 变量的声明有两种情况: 一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。 另一种是不需要建立存储空间的。 例如:extern int a 其中...
  • lile777
  • lile777
  • 2014年04月03日 15:59
  • 714

C语言中变量和函数的声明与定义

一、变量 在将变量前,先解释一下声明和定义这两个概念。声明一个变量意味着向编译器描述变量的类型,但并不为变量分配存储空间。定义一个变量意味着在声明变量的同时还要为变量分配存储空间。在定义一个变量的同...

C语言声明,定义,赋值,初始化

摘自:http://blog.csdn.net/zlhy_/article/details/8442573 我想不管是现在学C系语言的人,还是学习Java等以及其他语言的人最初的入门语言应该...

C语言细节之定义与声明

什么是定义什么是声明,似乎这俩个东西一样但是又有所区别,思考一下,如果你不能直接说出这二者的根本区别,那么本文对你还是有点用处的。 首先什么是定义?《C++Primer》第四版 2.3.5节中这么说...

C语言声明与定义

很久没接触C语言了,今天遇到声明与定义的问题,于是找到下面的解释: 声明(declaration )指定了一个变量的标识符,用来描述变量的类型,是类型还是对象,或者函数等。声明,用于编译器(comp...
  • ccq1029
  • ccq1029
  • 2015年01月24日 13:36
  • 811

C语言 全局变量定义与声明

用C语言编写程序的时候,我们经常会遇到这样一种情况:希望在头文件中定义一个全局变量,然后包含到两个不同的c文件中,希望这个全局变量能在两个文件中共用。   举例说明:项目文件夹project下有ma...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C语言——符号的声明与定义
举报原因:
原因补充:

(最多只允许输入30个字)