我总是组织我的C源的方法是将结构,宏和函数原型放在头文件和.c文件中的函数实现中。但是,我最近一直在阅读大量项目的其他人的代码,我开始看到人们经常在C源本身中定义诸如结构和宏之类的东西,紧接在使用它的函数之上。我可以看到一些好处,因为你不必去寻找特定函数使用的结构和宏的定义,一切都在与使用它的函数大致相同的地方。但是我也可以看到它的一些缺点,因为它意味着没有一个用于结构/宏定义的中央存储库,因为它们分散在源代码中。
我的问题是,决定何时将宏/结构定义放在C源代码中而不是头文件本身有什么好的经验法则?
答案 0 :(得分:29)
通常,您放在头文件中的所有内容都是接口的一部分,而您放在源文件中的所有内容都是实现的一部分。
也就是说,如果头文件中的某些内容仅被关联的源文件使用,则它是移动到该源文件的绝佳选择。这样可以防止“污染”每个使用标头的文件的名称空间,以及它们从未打算使用的宏和类型。
答案 1 :(得分:12)
Interfaces and implementations就是它的全部内容。
接受答案的附录:在标题中放置不完整的结构声明可能很有用,但只将定义放在.c文件中。现在,指向该结构的指针为您提供了一个完全控制的私有类型。非常有用,可以保证关注点的分离;有点像C ++中的私有成员。
有关大量示例,请点击链接。
答案 2 :(得分:8)
将您的公共结构和界面放入.h文件中。
将您的私有位放入.c文件中。
如果我有多个实现逻辑功能集的.c文件,我会将需要在这些实现文件中共享的内容放入*p.h
文件中('p'表示私有) 。客户端代码不应包含* p.h标头。
例如,如果我有一组实现XML解析器的例程,我可能会有以下组织:
xmlparser.h - the public structures, types, enums, and function prototypes
xmlparserp.h - private types, function prototypes, etc. that client code
doesn't and shouldn't need
xmlparser.c - implementation of the XML parser
xmlutil.c - some other implementation bits (would include xmlparserp.h)
答案 3 :(得分:6)
很多人不知道这个基本的东西BTW,这是在任何规模的C项目上保持理智所必需的。
答案 4 :(得分:4)
主要是,手头的问题是一种封装考虑因素。您可以将模块的头文件看作不是它的“开销”,这就是您现在正在做的事情,就像它的公共接口声明一样,这可能是您正在查看的代码正在看到它的人。
从那里开始,头文件中的内容自然是其他模块需要了解的内容:您期望在外部使用的函数的原型,用于接口目的的结构和宏,外部变量声明等等,而对于模块内部使用严格的事情则放在.c
文件中。
答案 5 :(得分:4)
在David Straker的“C风格:标准和指南”(可在线提供here)一书中,对文件布局以及C文件和标题之间的划分有一些好的想法。
您可以阅读chapter 7,特别是第7.4章。
正如John Calsbeek所说,你可以根据你的组织如何使用标题部分。 如果一个结构,类型,宏,......仅由一个源使用,则可以在那里移动代码。
你可能有原型的头文件和一些常用声明的头文件(类型定义等等)
答案 6 :(得分:2)
如果在.c中定义结构和宏,则无法从其他.c文件中使用它
要这样做,你必须将它放在.h中,以便#include告诉编译器在哪里检查你的结构和宏
除非你#include“x.c”,你不应该这样做=)