//jia.h
int jia(int a,int b);
//jia.c
int jia(int a,int b)
{
return a+b;
}
//test.c
#include<stdio.h>
#include "jia.h"
int main()
{
printf("%d\n",jia(1,1));
}
用gcc命令编译test.c(单独用gcc编译一个文件,默认包含了链接的过程,如果只想编译,而不链接,要加-c参数)
gcc test.c
会出现如下错误
/tmp/ccBJQ1Z1.o: In function `main':
test.c:(.text+0x19): undefined reference to `jia'
collect2: error: ld returned 1 exit status
可以发现是错误的引用,连接器ld出错,因为没有找到函数jia的实现文件,需要指出的是#include仅仅添加了一个函数的声明,关于jia的实现,编译器不知道任何信息,因此要手动给出链接信息,正确的做法是,分别编译test.c和jia.c,然后把生成的两个目标文件链接起来。
gcc -c test.c
gcc -c jia.c
gcc test.o jia.o -o test
以下部分转载自http://www.cnblogs.com/webcyz/archive/2012/09/16/2688035.html
要理解头文件,主要是要理解“声明”
C/C++中,所有使用到得变量、函数、类都要是声明过得,就是说,要有一行语句来告诉编译器,我有一个名字叫XXX的???类型的变量(函数、类)。
然后还有一个因素就是,在编译的时候,程序是按照每个.C或.CPP文件单独编译的。
也就是说,对于每个C文件中,如果都用到了同一个函数(比如printf),那么,我在每个对应文件中写一遍printf的声明明显是很麻烦的。所以我把这个声明单独写了一个文件,为了区别,我把扩展名记做.h,在需要使用对应的函数(类)的时候,我就不需要去拷贝函数的声明,而只需要#include对应头文件就可以了,系统自动帮你拷贝进来——C语言提供的头文件,按照函数功能分类好了,比如数学函数就都写在了math.h里面,一包含就全包含,不管你用没用到cos()这个函数或者其他什么。
当然,由于.h文件中也可以包含其他.h文件,所以为了不重复声明或定义,需要用宏做相应的处理,这个不是要理解的东西,而是照着写。
编译的时候,gcc做的比我们想得多得多(包括了链接),想查看gcc都做了什么,添加-v选项,而ld命令仅仅是链接,它不知到main为入口点。
gcc -v -o test test.c
通常编译器并不要求函数一定要在被调用之前定义,编译器在处理到某个未知类型的函数时,会为其创建一个隐式声明,并假设该函数返回值类型为int。但编译器无法检查传递给该函数的实参类型和个数是否正确,所以这不利于编译器为我们排除错误。而且在VC编译器下,这样的代码会编译出错,一般可能提示“ error C2371: 'function1' : redefinition; different basic types”,因为编译器隐式声明了一个function1,VC编译器在后面遇到真实的function1定义时,真实的function1返回值并不是int,而是void。所以VC编译器认为function1函数重定义(redefinition)了。
C99遵循这样的规则:在调用一个函数之前,必须先对其进行声明或定义。调用函数时,如果此前编译器未见到该函数的声明或定义,会导致出错。”
所以,综上所述,尽管在gcc编译器中这样的代码仍然可以编译通过并且正确执行。也最好还是遵循这样的规则:在函数调用前,先对其定义或声明。
通过以上内容分析,我们可以知道,在调用一个函数之前,最好对其进行声明或者定义!!!