|
|
1
36
接口文件 如果您只需要某个.c文件中的函数(不在任何其他模块中),请将其作用域声明为静态。这意味着只能从定义它的c文件中调用它。
例如:
#include "Module1.h"
static void MyLocalFunction(void);
static unsigned int MyLocalVariable;
unsigned int MyExternVariable;
void MyExternFunction(void)
{
MyLocalVariable = 1u;
/* Do something */
MyLocalFunction();
}
static void MyLocalFunction(void)
{
/* Do something */
MyExternVariable = 2u;
}
模块1.h: #ifndef __MODULE1.H
#define __MODULE1.H
extern unsigned int MyExternVariable;
void MyExternFunction(void);
#endif
模块2.c #include "Module.1.h"
static void MyLocalFunction(void);
static void MyLocalFunction(void)
{
MyExternVariable = 1u;
MyExternFunction();
}
|
|
|
2
10
试着让每个.c都专注于特定的功能领域。使用相应的.h文件来声明这些函数。 每个.h文件的内容周围都应该有一个“头”保护。例如:
通过这种方式,您可以根据需要多次包含“accounts.h”,并且第一次在特定编译单元中看到它时,将是唯一一次真正提取其内容的编译单元。 |
|
|
3
7
编译程序您可以在以下位置看到C“模块”的示例: this topic -请注意,有两个文件-头文件tea.h和代码tea.c。您可以在标头中声明希望其他程序访问的所有公共定义、变量和函数原型。在您的主项目中,您将#包括并且该代码现在可以访问标题中提到的tea模块的函数和变量。
连接器当您编译两个单独的C文件时,编译器会生成单独的对象文件——因此main.C变成main.o,tea.C变成tea.o。链接器的工作是查看所有对象文件(main.o和tea.o),并匹配引用-因此,当您在main中调用tea函数时,链接器会修改该调用,以便它确实在tea中调用正确的函数。链接器生成可执行文件。 great tutorial 这将更深入地讨论这个主题,包括范围和您将遇到的其他问题。
-亚当 |
|
|
4
7
开始时有两条简单的规则:
|
|
|
5
3
编译器主要与头文件无关。每次调用编译器都会将源(.c)文件编译成对象(.o)文件。幕后(即在
源文件
|
|
|
6
3
与上面提供的答案一样,将代码分成模块(单独的文件)的一个小优点是,如果必须有任何全局变量,可以使用关键字“static”将其范围限制为单个模块。(您也可以将此应用于函数)。请注意,“static”的这种用法不同于它在函数中的用法。 |
|
|
7
1
你的问题清楚地表明,你还没有真正做过很多认真的开发工作。通常情况下,您的代码通常太大,无法放入一个文件中。一个很好的规则是,您应该将功能划分为逻辑单元(.c文件),每个文件中包含的内容不应超过您一次可以轻松保存在头脑中的内容。 一个给定的软件产品通常包括许多不同的.c文件的输出。通常情况下,编译器会生成许多对象文件(在unix系统中为“.o”文件,VC生成.obj文件)。“链接器”的目的是将这些对象文件组成输出(共享库或可执行文件)。 通常,实现(.c)文件包含实际的可执行代码,而头文件(.h)在这些实现文件中包含公共函数的声明。您可以很容易地拥有比实现文件更多的头文件,有时头文件也可以包含内联代码。 实现文件之间相互包含通常是很不寻常的。一个好的实践是确保每个实现文件将其关注点与其他文件分开。 我建议您下载并查看linux内核的源代码。对于一个C程序来说,它是相当庞大的,但是可以很好地组织成不同的功能领域。 |
|
|
8
0
.h文件应用于定义函数的原型。这是必要的,这样您就可以在C文件中包含所需的原型,而无需在一个文件中声明所需的所有函数。
例如,当你
如果您只编写功能不多的琐碎应用程序,那么实际上没有必要将所有内容模块化为过程的逻辑分组。但是,如果您需要开发一个大型系统,那么您需要考虑在何处定义每个功能。 |