在K&R书(p59)(编辑:第二版,涵盖ANSIC),建议将较大的项目拆分为多个文件更容易。在每个文件中,像往常一样,顶部包括几个库:例如,getop.c需要stdio.h,stack.c也需要,main.c也需要。
这些片段是这样的:
//main.c
#include <stdio.h>
#include <stdlib.h>
#include "calc.h"
int main(void)
{
//etc
}
//getop.c
#include <stdio.h>
#include <ctype.h>
#include "calc.h"
getop()
{
/*code*/
}
//stack.c
#include <stdio.h>
#include "calc.h"
void push(double val)
{
//code
}
我很难弄清楚在一个项目中多次包含标准库是如何工作的。当然,为了让自定义.c文件能够访问内置函数,我们需要包括#include <header.h>
,以便他们知道printf()
和getchar()
的存在等等,但是如果stdio.h
被包括四次而不是一次(如果所有内容都放在一个文件中),这种方法不会增加最终程序的大小吗?
K&R确实指出,将一个程序拆分为多个文件最终会使维护所有.h文件变得更加困难。
我想我真正想问的是编译器如何解决一个库在一个项目中多次被#包含的问题。
我已经阅读了关于使用include-guard的内容,但这似乎不需要用于此实现,因为它们处理的是确保相同的代码位不会被包含两次,如:
文件"module.h"
#ifndef MODULE_H
#define MODULE_H
struct foo {
int member;
};
#endif /* MODULE_H */
文件"mod2.h"
#include "module.h"
文件"prog.c"
#include "module.h"
#include "mod2.h"
参考
我想我真正想问的是编译器如何解决一个库在一个项目中多次被#包含的问题。
#include <stdio.h>
不包含库,只包含它的声明,所以编译器知道存在什么函数。链接器负责包含一个库并将所有内容组合在一起。
因为他们使用了一种名为include guard的东西,假设您自己的include文件不止一次被包含在其中,那么您就可以执行这个
MyHeader.h
#ifndef MY_HEADER_H
#define MY_HEADER_H
/* file content goes here */
#endif /* MY_HEADER_H */
然后你有另一个标题
**AnotherHeader.h**
#ifndef MY_ANOTHER_HEADER_H
#define MY_ANOTHER_HEADER_H
#include "MyHeader.h"
/* file content goes here */
#endif /* MY_ANOTHER_HEADER_H */
和在你的程序
main.c
/*
* MY_HEADER_H is undefined so it will be defined and MyHeader.h contents
* will be included.
*/
#include "MyHeader.h"
/*
* MY_HEADER_H is defined now, so MyHeader.h contents will not be included
*/
#include "AnotherHeader.h"
int main()
{
return 0;
}
由于包含的文件在每个编译单元中只包含一次,因此产生的二进制大小不会增加,此外,包含头文件只会增加编译文件的大小,例如,当在这些头文件中声明了字符串文字时,否则它们只会向编译器提供有关如何调用给定函数的信息,即如何将参数传递给它以及如何存储它的返回值。