在另一个.c
文件中#include
一个.c
文件是否可以(甚至建议/好的实践)?
在另一个.c
文件中#include
一个.c
文件是否可以(甚至建议/好的实践)?
如果使用得当,这可以是一种有用的技术。
假设您有一个复杂的、性能关键的子系统,具有相当小的公共接口和大量不可重用的实现代码。代码运行到几千行,有一百多个私有函数和相当多的私有数据。如果您使用非平凡的嵌入式系统,您可能经常处理这种情况。
您的解决方案可能是分层、模块化和解耦的,这些方面可以通过在不同的文件中编码子系统的不同部分来有用地表示和强化。
使用 C 时,这样做可能会失去很多。几乎所有的工具链都为单个编译单元提供了良好的优化,但对于任何声明为 extern 的内容都非常悲观。
如果将所有内容放入一个 C 源模块中,则会获得以下优点:
性能和代码大小的改进 - 在许多情况下,函数调用将被内联。即使没有内联,编译器也有机会生成更有效的代码。
链接级别的数据和函数隐藏。
避免命名空间污染及其必然结果 - 您可以使用较少笨重的名称。
更快的编译和链接。
但是,当涉及到编辑此文件并且失去了隐含的模块化时,您也会得到一个混乱不堪的结果。这可以通过将源代码拆分为多个文件并包含这些文件以生成单个编译单元来克服。
但是,您需要强制执行一些约定以正确管理此过程。这些约定在某种程度上取决于您的工具链,但一些常见的指针是 -
将公共接口放在单独的头文件中 - 无论如何,您都应该这样做。
有一个主要的.c文件,其中包括所有子文件。这也可以包括公共接口的代码。
使用编译器保护程序确保私有头文件和源模块不被外部编译单元包含。
所有私有数据和函数都应声明为静态。
保持.c和.h文件之间的概念区别。这利用了现有的约定。区别在于您的头文件中将有很多静态声明。
如果您的工具链没有任何理由不这样做,请将私有实现文件命名为.c和.h。如果您使用包含保护程序,这些文件将不会产生代码并且不会引入新名称(您可能会在链接期间得到一些空段)。巨大的优势是其他工具(例如IDE)将适当地处理这些文件。
这会编译吗?可以,它能够成功编译。
这是否推荐?不推荐 - .c文件会被编译成.obj文件,然后由链接器将它们在编译后链接在一起形成可执行文件(或库),所以没有必要在一个.c文件中包含另一个.c文件。相反,您可能想做的是制作一个.h文件,列出其他.c文件中可用的函数/变量,并将该.h文件包含进去。
不行。
根据您使用的构建环境(您没有具体说明),您可能会发现它按照您想要的方式正常工作。
然而,有许多环境(包括IDE和大量手工制作的Makefile)期望编译 *.c 文件-如果发生这种情况,由于重复符号,您可能最终会遇到链接器错误。
通常情况下应该避免这种做法。
如果您绝对必须 #include 源代码文件(一般来说应该避免),请使用不同的文件后缀名。
您可以使用Linux中的gcc编译器将两个c文件链接成一个输出。假设你有两个c文件,一个是'main.c',另一个是'support.c'。因此,连接这两个文件的命令为:
gcc main.c support.c -o main.out
通过这两个文件,将链接到一个单独的输出文件 main.out。 运行输出文件的命令为:
./main.out
如果您在main.c中使用了support.c文件中声明的函数,则还应在main中使用extern存储类来声明它。
我想分享一个团队决定包含.c文件的情况。我们的架构主要由通过消息系统解耦的模块组成。这些消息处理程序是公开的,并调用许多本地静态工作函数来完成它们的工作。问题出现在尝试为我们的单元测试用例获取覆盖率时,因为唯一间接执行此私有实现代码的方式是通过公共消息接口。由于某些工作函数深入堆栈,因此达到适当覆盖率这转变成了一场噩梦。
包含.c文件给了我们一种方法来达到我们感兴趣的测试中机器关键部分。
/**
* @file vendor_wrap.c
* @brief vendor source code wrapper to prevent warnings
*/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnested-externs"
#include "vendor_source_code.c"
#pragma GCC diagnostic pop
gcc main.c vendor_wrap.c -o $(CFLAGS) main.out
C语言并不禁止那种#include,但是生成的翻译单元仍然必须是有效的C。
我不知道你正在使用什么带有.prj文件的程序。如果你正在使用像“make”或Visual Studio之类的东西,只需确保将其要编译的文件列表设置为不包含无法独立编译的文件即可。