在 K&R 书(第 59 页)(编辑:第二版,涵盖 ANSI C)中,建议将较大的项目拆分为多个文件更容易。在每个文件中,几个库像往常一样包含在顶部:例如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 多次的问题。
我已经阅读了使用 include Guards 的内容,但似乎这个实现不需要这样做,因为它们负责确保相同的代码位不会被包含两次,如下所示:
文件“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 多次的问题。
您不通过
#include <stdio.h>
包含库,您只需包含它的声明,因此编译器知道存在哪些函数。链接器负责包含一个库并将所有内容放在一起。
因为他们使用了称为 include Guards 的东西,假设你自己的包含文件要被包含多次,那么你可以这样做
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;
}
由于每个编译单元仅包含一次包含的文件,因此生成的二进制大小不会增加,此外,包含头文件只会增加编译文件的大小,例如在这些头文件中声明了字符串文字,否则它们仅提供信息编译器关于如何调用给定函数,即如何向其传递参数以及如何存储其返回值。