extern与函数
先来理解2个概念:
外部函数:如果在当前文件中定义的函数允许其他文件访问、调用,就称为外部函数,c语言规定,不允许有同名的外部函数。
内部函数:如果在当前文件中定义的函数不允许其他文件访问、调用,只能在内部使用,就称为内部函数。c语言规定不同的源文件可以有同名的内部函数,并且互不干扰。
下面说明在一个源文件中调用另一个源文件的函数,比如在main.c中调用one.c中定义的one函数。
1.首先,在one.c中定义一个one函数
如果你想让这个one函数可以被main.c访问,那么one函数就必须是外部函数。完整的定义是要加上extern关键字。
one.c:
#include <stdio.h>
extern void one()
{
printf("调用了one函数");
}
不过这个extern完全可以省略,因为默认情况下,所有的函数就是外部函数。我们可以简化一下:
one.c:
#include <stdio.h>
void one()
{
printf("调用了one函数");
}
2.接下来,我想在main.c的main函数中,调用one.c中的one函数
怎样才能调用one.c中的one函数呢?你可能会产生2个想法:
想法1:直接在main函数中写上one();
main.c:
#include <stdio.h>
int main()
{
one();
return 0;
}
这个做法肯定不行,因为main函数根本不知道one函数的存在,怎么调用呢?这个在标准C编译器里面会报错的,但是在Xcode中只是个警告。
想法2:在main.c中包含one.c文件
main.c:
#include <stdio.h>
#include <one.c>
int main()
{
one();
return 0;
}
大家都知道#include的作用纯粹就是内容拷贝,所以又相当于
main.c:
#include <stdio.h>
void one()
{
printf("调用了one函数");
}
int main()
{
one();
return 0;
}
哎,这么一看好像是对的哦,在main函数前面定义了个one函数,然后在main函数中调用了这个one函数。从语法上看是对的,所以编译是没问题的。但是这个程序不可能运行成功,因为在链接的时候会报错。我们已经在one.c中定义了one函数,现在又在main.c中定义one函数,C语言规定不允许有同名的外部函数,链接的时候链接器会发现在one.obj和main.obj中定义了同一个函数,会直接报错。
上面的2种想法都是不可行的,其实思路是一致的:让main函数知道one函数的存在。正确的做法应该是在main函数前面对one函数进行提前声明(看清楚,是声明,不是定义,定义和声明是两码事)。
3.在main函数前面对one函数进行提前声明
你想要把其他源文件中定义的外部函数拿过来声明,完整的做法,应该使用extern关键字,表示引用别人的"外部函数"
main.c:
#include <stdio.h>
extern void one();
int main()
{
one();
return 0;
}
运行程序,从控制台输出可以发现"one.c中定义的one函数"已经被"main.c的main函数"成功调用了。
也有人可能会马上冒出一个想法:假如除开one.c,还有其他源文件也有定义这个one函数怎么办?那main函数调用的究竟是谁的one函数啊?放心,绝对不会有这种情况,刚才不是说了么,不允许重复定义同一个外部函数,不然链接器会报错的,所以只会有一个外部one函数。
上述就是extern关键字对函数的作用:用来定义和声明一个外部函数。其实extern又跟auto一样废,完全可以省略。于是,我们可以简化成这样:
main.c:
#include <stdio.h>
void one();
int main()
{
one();
return 0;
}
重点:
为了模块化地开发,在正规的项目里面,我们会把one函数的声明写到另一个头文件中,当然,这个头文件的命名最好有意义、规范一点,比如叫one.h。以后,谁想调用这个one函数,包含one.h这个头文件就行了。于是最后的代码结构是这样的:
main.c:
#include <stdio.h>
#include "one.h"
int main()
{
one();
return 0;
}
one.c:
#include <stdio.h>
void one()
{
printf("调用了one函数");
}
one.h:
#ifndef _one_h
#define _one_h
void one();
#endif
|
|