上一篇文章中,通过头文件声明,而调用有一个特别大的漏洞:
为什么编译器可以链接过来呢,因为默认是extern修饰的,这种类似全局作用域的功能使其可以被调用
继续加强学习:
这一次有两对C文件:
first.c first.h
second.c second.h
first.c 代码:
//多文件测试 #include "head.h" #include <stdio.h> void printStr() { printf("Hello world! "); }
first.h代码:
void printStr(); //函数定义域:从声明点延伸到源程序文本结束
相应的,second.c 代码:
#include "second.h" #include <stdio.h> void main() { printStr(); }
second.h代码:(重点)
extern void printStr(); //函数定义域:从声明点延伸到源程序文本结束
分析:
无疑, 在上面的second.h和first.h中,需要我们用extern标志符来修饰printStr函数的声明,这样,printStr函数就可以被导出到连接程序, 也就是实现了无论在first.c文件中调用,还是在second.c文件中调用,连接程序都会很聪明的按照我们的意愿,把他连接到first.c文件中的printStr函数的定义上去, 而不必我们在second.c文件中也要再写一个一样的printStr函数.
但是,问题随之而来:
那么我们如何来区分哪个头文件中的声明在其对应的.c文件中有定义,而哪个又没有呢?这也许不是必须的,因为无论在哪个文件中定义,聪明的连接程序都会义无返顾的帮我们找到,并导出到连接程序, 但我觉得他确实必要的. 因为我们需要知道这个函数的具体内容是什么,有什么功能, 有了新需求后我也许要修改他,我需要在短时间内能找到这个函数的定义, 那么我来介绍一下在C语言中一个人为的规范:
在.h文件中声明的函数,如果在其对应的.c文件中有定义,那么我们在声明这个函数时,不使用extern修饰符, 如果反之,则必须显示使用extern修饰符.
这样,在C语言的.h文件中,我们会看到两种类型的函数声明. 带extern的,还不带extern的, 简单明了,一个是引用外部函数,一个是自己生命并定义的函数.
所以,在first.h 中 不使用extern修饰符(因为对应的.c文件有该子函数printStr的定义)
在second.h 使用extern修饰符