假设我有一个C程序,它被破坏为一组* .c和* .h文件。如果一个文件中的代码使用另一个文件中的函数,那么我应该在哪里包含头文件?在使用该函数的* .c文件中,或在该文件的标题内?
E.g。文件foo.c
包含foo.h
,其中包含foo.c
的所有声明; bar.c
和bar.h
相同。 foo1()
内的函数foo.c
调用bar1()
,该bar.h
在bar.c
中声明并在bar.h
中定义。现在的问题是,我应该在foo.h
内或foo.c
内包含{{1}}吗?
这些问题的一套好的经验法则是什么?
答案 0 :(得分:6)
你应该在foo.c中包含foo.h.这样,包含foo.h的其他c文件将不会不必要地携带bar.h。这是我对包含头文件的建议:
答案 1 :(得分:4)
正如其他人所说,标题foo.h应该声明能够使用源文件foo.c提供的功能所必需的信息。这将包括foo.c提供的类型,枚举和函数。 (你不使用全局变量,不是吗?如果你这样做,那么那些也在foo.h中声明。)
标题foo.h应该是自包含的和幂等的。自包含意味着任何用户都可以包含foo.h而不需要担心可能需要哪些其他头文件(因为foo.h包含那些头文件)。幂等意味着如果标题包含多次,则不会造成任何损害。这是通过经典技术实现的:
#ifndef FOO_H_INCLUDED
#define FOO_H_INCLUDED
...rest of the contents of foo.h...
#endif /* FOO_H_INCLUDED */
问的问题是:
文件foo.c包含foo.h,其中包含foo.c的所有声明;对于bar.c和bar.h也是如此。 foo.c中的函数foo1()调用bar1(),它在bar.h中声明并在bar.c中定义。现在的问题是,我应该在foo.h中包含bar.h,还是在foo.c中包含?
这取决于foo.h提供的服务是否依赖于bar.h。如果使用foo.h的其他文件需要bar.h定义的类型或枚举之一才能使用foo.h的功能,那么foo.h应该确保包含bar.h(通过包含它)。但是,如果bar.h的服务仅在foo.c中使用,并且使用foo.h的人不需要,则foo.h不应包含bar.h。
答案 2 :(得分:3)
我只会在头文件本身所需的* .h文件中包含头文件。在我看来,源文件所需的头文件应包含在源文件中,以便从源中明显看出依赖关系。应该构建头文件以处理多个包含,因此为了清楚起见,您可以将它放在两者中。
答案 3 :(得分:2)
我在.h
文件中包含了最小的标头集,并将其余标头包含在.c
文件中。这有利于减少编译时间。根据您的示例,如果foo.h
确实不需要bar.h
但是仍然包含它,而其他一些文件包含foo.h
,那么如果bar.h
更改,则会重新编译该文件,即使它实际上可能不需要或使用bar.h
。
答案 4 :(得分:2)
.h文件应该定义.c文件中函数的公共接口(也就是api)。
如果file1的接口使用file2的接口,那么#include file2.h在file1.h中
如果file1.c中的实现使用了file2.c中的东西,那么file1.c应该#include file2.h。
我必须承认 - 虽然我总是#include file1.h在file1.c中 - 我通常不会在file1.c中直接#including file2.h,如果它已经在file1.h中#included那么
如果您发现自己处于两个.c文件#include彼此.h文件的情况,那么这表明模块化已经崩溃,您应该考虑重组一些事情。
答案 5 :(得分:2)
使用foo.c
和foo.h
的示例我发现这些指南很有用:
请记住foo.h
的目的是促进foo.c
的使用,因此请尽可能简单,有条理,不言自明。请放心使用 以及 时使用foo.c
的功能 - 以及何时不来使用它们。< / p>
foo.h
声明foo.c
的公共功能:函数,宏,typedef和( shudder )全局变量。
foo.c
应该#include "foo.h
- 请参阅讨论,以及Jonathan Leffler在下面的评论。
如果foo.c
需要额外的标题才能编译,请将其添加到foo.c
。
如果要编译foo.h
需要外部标头,请将其包含在foo.h
利用预处理器阻止foo.h
被多次包含。 (见下文。)
如果由于某种原因需要外部标头才能让其他.c
文件使用foo.c
中的功能,请在foo.h
中添加标头以保存下一个开发者从不必要的调试如果您反对这一点,请考虑添加宏,如果未包含所需的标题,将在编译时显示指令。
不要在另一个.c
文件中包含.c
文件,除非您有非常充分的理由并清楚地记录下来
正如kgiannakakis所指出的,将公共接口与仅在foo.c
本身内所需的定义和声明分开是有帮助的。但是,不是创建两个文件,有时候让预处理器为您执行此操作会更好:
// foo.c
#define _foo_c_ // Tell foo.h it's being included from foo.c
#include "foo.h"
. . .
// foo.h
#if !defined(_foo_h_) // Prevent multiple inclusion
#define _foo_h_
// This section is used only internally to foo.c
#ifdef _foo_c_
. . .
#endif
// Public interface continues to end of file.
#endif // _foo_h_ // Last-ish line in foo.h