【问题标题】:Any good reason to #include source (*.c *.cpp) files?#include 源 (*.c *.cpp) 文件有什么好的理由吗?
【发布时间】:2011-03-14 17:06:03
【问题描述】:

我已经使用开源库(“fast artificial neural network”)工作了一段时间。我在我的静态库中使用它的源代码。然而,当我编译它时,我收到数百个链接器警告,这可能是由于库在其他 *.c 文件中包含它的 *.c 文件(因为我只包括一些我需要的头文件而我没有触及lib 本身的代码)。

我的问题:图书馆的开发人员是否有充分的理由使用这种强烈反对的方法? (或者至少我一生都被告知这很糟糕,根据我自己的经验,我认为这很糟糕)。还是只是糟糕的设计,这种方法没有任何收获?

我知道this related question,但它没有回答我的问题。我正在寻找可能证明这一点的理由。

一个额外的问题:有没有办法在不过多接触库代码的情况下解决这个问题?我有很多自己的工作,不想创作更多;)

【问题讨论】:

  • 链接器错误是否与您调用静态库中的函数有关?您可能想检查是否有公开的公共头文件供应用程序包含。否则静态库可能根本没有用。

标签: c include code-organization


【解决方案1】:

如果您曾在该 .c 文件中声明单个全局变量或函数,则不能将其包含在两个编译为相同二进制文件的位置,否则两个定义将发生冲突。如果它被包含在一个地方,它也不能被单独编译,同时仍被链接到与其用户相同的二进制文件中。

如果文件只包含在一个地方,为什么不把它变成一个离散的编译单元(并通过extern 声明使用它的全局变量)?为什么要费心把它包括在内?

如果你的 C 文件没有声明全局变量或函数,它们是头文件,应该这样命名。

因此,通过详尽的搜索,我可以说,唯一可能想要包含 C 文件的情况是,相同的 C 代码用于构建多个不同的二进制文件。即使在那里,您也在增加编译时间而没有真正的收益。

这是假设应该内联的函数被标记为inline,并且你有一个不错的编译器和链接器。

我不知道解决此问题的快速方法。

【讨论】:

    【解决方案2】:

    包含 C/C++ 代码会导致所有代码集中在一个翻译单元中。使用好的编译器,这可以大大提高速度(因为可以内联内容并优化函数调用)。

    但是,如果要像这样包含实际代码,它的大部分声明中都应该包含 static,否则会导致您看到的警告。

    【讨论】:

    • 赞成,因为您提供了一个很好的解释,但将另一个答案标记为正确,因为海报帮助解决了我遇到的问题:)
    【解决方案3】:

    我不知道那个库,但正如你描述的那样,它要么是不好的做法,要么是你对如何使用它的理解不够好。

    想要被其他人包含的 C 项目应始终为其他人提供结构良好的 .h 文件,然后提供用于链接的编译库。如果它想在头文件中包含函数定义,它应该将它们标记为 static(老式)或 inline(可能从 C99 开始)。

    【讨论】:

      【解决方案4】:

      我没有查看代码,但包含的 .c 或 .cpp 文件可能实际上包含在标头中工作的代码。例如,模板或内联函数。如果是这样,那么警告将是虚假的。

      【讨论】:

        【解决方案5】:

        据我所知 (grep '#include .*\.c'),他们只在 doublefann.c、fixedfann.c 和 floatfann.c 中这样做,并且每次都包含原因:

        /* Easy way to allow for build of multiple binaries */
        

        这种将预处理器用于简单复制粘贴的确切用途确实是包含实现 (*.c) 文件的唯一有效用途,而且相对较少。 (如果您出于其他原因想要包含一些代码,只需给它一个不同的名称,例如 *.h 或 *.inc。)另一种方法是在提供给编译器的宏中指定配置(例如 -DFANN_DOUBLE、-DFANN_FIXED 或-DFANN_FLOAT),但他们没有使用这种方法。 (每种方法都有缺点,所以我并不是说它们一定是错误的,我必须深入研究该项目才能确定。)

        他们提供的 makefile 和 MSVS 项目应该已经链接 doublefann.o(来自 doublefann.c)与 fann.o(来自 fann.c)或 fixedfann.o(来自 fixedfann.c) ) 等等,要么他们的文件搞砸了,要么类似的东西出了问题。

        您是否尝试从头开始创建项目(或使用现有项目)并将所有文件添加到其中?如果你这样做了,发生的事情是每个实现文件都被独立编译,并且生成的目标文件包含冲突的定义。这是处理实现文件的标准方式,许多工具都采用这种方式。唯一可能的解决方案是修复项目设置以不将它们链接在一起。 (好吧,你也可以彻底改变它们的来源,但这并不是真正的解决方案。)

        当您这样做时,如果您继续而不使用他们的项目设置,您可能会跳过编译 fann.c 等。人。并且可能只是从项目中删除它们就足够了——那么它们就不会被编译和链接。您需要准确地选择 一个 的 double-/fixed-/floatfann 来使用,否则会出现相同的链接错误。 (我没有看过他们的说明,但看​​到这个摘要在那里更深入地解释了一点,我不会感到惊讶。)

        【讨论】:

        • 感谢您的回复,我查看了他们的示例项目并找到了需要做的事情。从构建中排除包含其他 *.c 文件的这三个 *.c 文件解决了该问题,我的库编译良好(警告消失)并且使用该库的项目工作完美(使用 FANN 的部分输出正确)。非常感谢!
        • @Peter:欢迎您。我在这个答案中采取了另一种方式:而不是排除 double-/fixed-/floatfann.c,我现在看到我认为它们具有重要的设置,因此必须使用其中一个,但显然这不是真的。希望你能看到它是如何完成同样的事情的(避免与冲突的定义链接)。
        【解决方案6】:

        我目前正在家里这样做,因为我是 Linux 上 C++ 的新手,不想陷入链接器的困难中。但我不推荐它用于正常工作。

        (我也曾经不得不将 header.dat 包含到 C++ 程序中,因为 Rational Rose 不允许标头成为已发布软件的一部分,并且我们需要运行系统上的特定源文件(出于神秘原因) .)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-17
          • 2014-06-24
          • 2010-12-12
          • 1970-01-01
          • 1970-01-01
          • 2012-10-13
          • 2010-11-11
          • 1970-01-01
          相关资源
          最近更新 更多