是否可以将.c文件包含在另一个.c文件中?

时间:2012-08-07 16:05:26

标签: c struct include

例如:

file1.c有:

static const struct 
{ 
   int a;
   int b;
   int c;
} mystruct = { 1, 2, 3};

file2.c有:

#include <stdio.h>
#include "file1.c"

等等。

可以吗?

8 个答案:

答案 0 :(得分:7)

  

这样做可以吗?请告诉我。感谢。

这在技术上会起作用,但我不推荐它。相反,我建议将你的声明放在头文件中,然后在你的project / makefile / etc中包含两个.c文件。

这将是一种“标准”的工作方式,这反过来又使您的项目更易于维护。

答案 1 :(得分:3)

是的,如果您有良好的动机,那就没关系。例如,它可以帮助您避免源代码重复(即使您仍然会在二进制级别获得重复),或者它可能允许您处理机器生成的代码片段(例如,由单独的编译器生成的解析器) )。您甚至可以在某些平台上获得一些性能或占用空间的改进,因为编译器可以选择更优化的指令(例如,file1.c包含代码的情况下的相对,本地调用),如果file1.c是{单独的翻译单位。

如果你的动机不够好,就应该避免,因为这可能会在一些方面造成麻烦。我想到的一些事情是:

  • 您的构建系统可能不够智能,无法检测到file1.c
  • 存在依赖关系
  • 您的编辑器或开发环境可能不够智能,无法找到file1.c
  • 中的符号 如果您在其中定义的所有符号都没有内部链接,则
  • file1.c可能会导致链接错误。

答案 2 :(得分:1)

避免这样做。将项目的其他部分中对 file1.c 有用/必要的任何类型定义和函数签名拖到一个公共头文件中,而不是包含在项目的其他部分中。

通常在 file2.c 中包含 file1.c 将起作用,因为文件包含就是这样,将#include替换为另一个文件的内容,但随着项目复杂性的增加,这将开始中断,并且您开始遇到多重定义符号的问题。

答案 3 :(得分:1)

我建议虽然有时#include包含实际代码或数据定义的文件(与声明不同),但我不喜欢用.c扩展名命名文件,除非它们旨在直接编译。我通常将文件命名为#include'd,但包含的声明不仅仅是声明,扩展名为“.i”。例如,在我使用的一个嵌入式处理器上,访问静态结构元素的代码大约是给定结构指针的元素大小的四分之一,并且运行速度大约是访问给定结构指针的元素的代码的四倍。因此,如果存在可以在结构上运行的大量代码块,则代码需要合理地快速运行,并且代码可能必须在其上运行两个结构,生成代码的单独副本更有效。对于这两个结构而不是生成一个可以使用任何一个代码的代码(如果速度不是一个问题,那么就有可能在其中一个结构上运行代码,以及交换结构内容的例程。在第二个结构上运行,交换结构,在第一个结构上运行,然后将它们交换回来。)

我实现这个习惯用法的首选方法是做类似的事情:

#define THINGIE 0
#define THINGIE_STRUCT thingie0
#include "thingie.i"
#undef THINGIE_STRUCT
#undef THINGIE

#define THINGIE 1
#define THINGIE_STRUCT thingie1
#include "thingie.i"
#undef THINGIE_STRUCT
#undef THINGIE

有点难看,但有时候在间接结构访问非常糟糕的机器上是值得的。

答案 4 :(得分:0)

不,你总是应该避免包含一个c文件。

头文件应仅包含定义/原型。

c文件包含函数,不应包含在内。

答案 5 :(得分:0)

从技术上讲,它只是一个文件的名称, .c 扩展名对文件内容没有影响,如果你愿意,可以称之为 .z 。所以回答你的问题:是的,你可以做到。但它确实违反惯例,它应该在头文件中。

答案 6 :(得分:0)

你可以在这里找到一个很好的答案:

Including one C source file in another?

我自己将它保存为头文件file1.h,并包含它。

答案 7 :(得分:0)

这里基本上没有技术考虑因素。也就是说,该决定基本上与软件或硬件的运行方式无关。

本决定中的考虑因素是人为因素。当我们制定决策并创建有关如何组织源代码的约定时,我们这样做是为了实现以下目标:使代码更容易编写。使代码更易于维护。减少错误。

这些都是人为考虑因素。人类在某些方面表现与完美机器不同:他们会犯错误。他们忘记了事情。它们可以更好地处理分成易于管理的大小的问题。

通常,头文件用于声明在多个源文件中使用的东西(例如许多不同人在许多不同程序中使用的库例程)并将声明与定义分开,以便您可以编译使用例程的源文件,而不必在源文件中包含这些例程的定义。从技术上讲,您可以将声明复制到每个源文件中,您将从编译器获得相同的结果。但是这违反了几个目标:它使代码更难编写,因为只要对例程定义进行更改,就必须更改声明的所有副本。它会增加错误:有时,人们会忘记或遗漏需要更改的副本之一。

因此,您可以将结构对象的定义放入.c文件中。您也可以将其放入头文件中。这会帮助你实现目标吗?

请注意,struct对象声明为static。如果它在多个源文件中编译,则生成的每个目标文件都将具有单独的副本。将目标文件链接到单个可执行文件时,它将具有相同数据的多个副本(除非您使用的开发人员工具非常非常好)。这是一种浪费,所以这不是一个好主意。但是,如果您只在一个源文件中编译它,那么只有人为考虑因素很重要:您是否有可能犯错并编译file1.c和file2.c?当其他人处理这段代码时,他们会理解mystruct的定义方式和原因吗?等等。

我曾参与过在单独的源文件中定义对象的项目。例如,有时需要准备一份计算数据表并将其包含在程序源中。在这种情况下,将该表保存在单独的源文件中是合理的。

通常情况下,在这种情况下使用的解决方案是使用仅包含表定义的源文件,而不使用其他任何内容。在该源文件中,使用“extern”关键字将表声明为外部表。在头文件中,表将被声明但未定义。使用该表的每个源文件都包含用于声明表的头文件。定义表的源文件还包括头文件。 (当你这样做时,如果头文件和源文件之间有任何不匹配,编译器会抱怨。这可以避免头文件中的错误。)

定义表的源文件将被编译为对象模块。包含程序其他内容的源文件将被编译为单独的对象模块。然后链接器用于将所有对象模块组合成一个程序。

在您的情况下,是否有任何理由声明对象是静态的?如果有,那么将其定义包含在另一个源文件中的解决方案可能是合适的。但是,出现这种情况的情况很少见。如果您认为将定义放在单独的文件中对您的组织源有帮助,那么更合适的解决方案是将对象声明为外部,如上所述,并单独编译源。

使用GCC时,您可以将源代码模块编译为:

  

gcc -c -o name0.o name0.c   gcc -c -o name1.o name1.c

“ - c”开关显示“只需编译到对象并停止,而不是执行下一步链接以生成可执行文件。”“ - o”开关指定输出文件的名称。

然后,您可以将对象模块链接到这样的可执行文件:

  

gcc -o program name0.o name1.o