【问题标题】:is it ok to include a .c file in another .c file?可以在另一个 .c 文件中包含一个 .c 文件吗?
【发布时间】:2012-08-04 16:45:35
【问题描述】:

例如:

file1.c 有:

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

file2.c 有:

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

等等。

这样可以吗?

【问题讨论】:

  • 你不需要给你的变量命名吗?!
  • 一般来说,不,这不行。为什么要这样做?
  • 它可以工作......但丑得要命。不要这样做!
  • 为什么file1 还是一个.c 文件?

标签: c struct include


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢,但是 .c 文件如何?我的意思是如何 2 .c 文件?
  • @RRR 使用生成文件。见:cs.colby.edu/maxwell/courses/tutorials/maketutor
  • 谢谢,但 file1.c 只有结构定义。没事吧?
  • @RRR 你应该把它放在头文件(.h)中。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    我建议,虽然有时#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 事情

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

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

        Including one C source file in another?

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

        【讨论】:

        • 您链接的问题实际上似乎与此问题完全相同。
        【解决方案6】:

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

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

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

        【讨论】:

        • 现在,我的 .c 文件只包含结构定义。还是不行吗?
        • 它不仅包含定义,还包含声明。
        • 您可能必须在一个文件中使用 extern 关键字,而在另一个文件中使用实际声明。类型本身(结构)可以留在头文件中。
        【解决方案7】:

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

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

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

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

        因此,您可以将结构对象的定义放入 .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

        【讨论】:

          【解决方案8】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-04-28
            • 2010-09-18
            • 2011-06-23
            • 2013-04-23
            • 1970-01-01
            • 1970-01-01
            • 2011-03-11
            • 2010-10-19
            相关资源
            最近更新 更多