0

For example:

file1.c has:

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

file2.c has:

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

and so on.

Is this OK to do?

4

8 回答 8

8

这可以吗?请告诉我。谢谢。

这在技术上可行,但我不推荐它。相反,我建议将您的声明放在头文件中,然后将两个 .c 文件都包含在您的项目/makefile/etc 中。

这将更像是一种“标准”的工作方式,从而使您的项目更易于维护。

于 2012-08-07T16:07:53.757 回答
4

是的,只要您有良好的动机,就可以。例如,它可以帮助您避免源代码重复(即使您仍然会在二进制级别获得重复),或者它可以允许您使用机器生成的代码片段(例如,由单独的编译器生成的解析器)。您甚至可以在某些平台上获得一些性能或占用空间的改进,因为编译器可以选择更优化的指令(例如,如果是单独的翻译单元,则这些指令file1.c是不可能的。file1.c

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

  • 您的构建系统可能不够智能,无法检测到依赖于file1.c
  • 您的编辑器或开发环境可能不够聪明,无法从file1.c
  • file1.c如果不是您在其中定义的所有符号都具有内部链接,则可能会导致链接错误。
于 2012-08-07T16:28:14.990 回答
2

我建议虽然有时#include 一个包含实际代码或数据定义的文件(与仅声明不同)很有用,但我不喜欢用 .c 扩展名命名文件,除非它们是经过设计的可以直接编译。我通常将设计为#include 的文件命名,但包含的不仅仅是声明,扩展名为“.i”。例如,在我使用的一个嵌入式处理器上,访问静态结构元素的代码大约是访问给定结构指针的元素的代码的四分之一,运行速度大约是其四倍。因此,如果有大量代码块可以对结构进行操作,则代码需要合理快速地运行,并且代码可能必须在两个结构上进行操作,

我首选的实现这个习惯用法的方法是:

#define 事情 0
#define THINGIE_STRUCT thingie0
#include "thingie.i"
#undef THINGIE_STRUCT
#undef 事情

#define 事情 1
#define THINGIE_STRUCT thingie1
#include "thingie.i"
#undef THINGIE_STRUCT
#undef 事情

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

于 2012-08-08T20:51:16.397 回答
1

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

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

于 2012-08-07T16:15:44.363 回答
0

不,您始终应避免包含 ac 文件。

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

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

于 2012-08-07T16:07:18.610 回答
0

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

于 2012-08-07T16:07:42.330 回答
0

您可以在这里找到问题的好答案:

在另一个中包含一个 C 源文件?

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

于 2012-08-07T16:09:52.793 回答
0

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

该决定中的考虑是人类的考虑。当我们就如何组织源代码做出决定并制定惯例时,我们这样做是为了实现以下目标: 使代码更易于编写。使代码更易于维护。减少错误。

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

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

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

请注意,结构对象被声明为静态的。如果它在多个源文件中编译,则生成的每个目标文件都将有一个单独的副本。当您将目标文件链接到单个可执行文件中时,它将具有相同数据的多个副本(除非您使用的开发人员工具非常非常好)。这是一种浪费,所以这不是一个好主意。但是,如果您只在一个源文件中编译它,那么只有人为因素才重要:您是否有可能犯错误并同时编译 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 程序名0.o name1.o

于 2012-08-07T16:54:18.300 回答