【问题标题】:Two basic question about compiling and libraries关于编译和库的两个基本问题
【发布时间】:2009-08-27 10:22:09
【问题描述】:

我有两个半相关的问题。

我的第一个问题:我可以通过以下方式调用标准库中的函数而无需编译整个库:

#include <stdio.h>

我将如何对我的头文件做同样的事情?仅仅“包含”我的纯文本头文件显然是行不通的。

#include "nameofmyheader.h"

基本上,我怎样才能创建一个其他文件可以调用的库?

第二个问题:假设我有一个程序被分成50个c文件和一个头文件。除此之外,还有什么正确的编译方法:

cc main.c 1.h 1.c 2.c 3.c 4.c 5.c 6.c 7.c   /*... and so on*/

请纠正我的任何误解。我完全迷路了。

【问题讨论】:

  • 您使用的是什么平台?如果是 Windows,我建议构建一个静态库或 DLL,您可以从中链接外部代码,但这些是特定于 Windows 的

标签: c


【解决方案1】:

首先,您对#include 会发生什么感到有些困惑。您永远不会“编译”标准库。标准库已经编译并位于库文件中(Windows 上的 .dll 和 .lib 文件,Linux 上的 .a 和 .so 文件)。 #include 的作用是为您提供链接 到标准库所需的声明

首先要了解#include 指令是它们非常低级。如果您使用 Java 或 Python 编程,#includes 与导入有很大不同。导入在较高级别告诉编译器“此源文件需要使用此包”,编译器会弄清楚如何解决该依赖关系。 C 指令中的#include 表示“获取此文件的全部内容并在编译时将其粘贴到此处。”特别是,#include &lt;stdio.h&gt; 引入了一个文件,该文件包含标准库中所有 I/O 函数的前向声明。然后,当您编译代码时,编译器知道如何调用这些函数并检查它们的类型正确性。

一旦您的程序被编译,它就会链接到标准库。这意味着您的链接器(由您的编译器自动调用)将导致您的可执行文件使用共享标准库(.dll 或 .so),或者将复制静态标准库(.lib 或.a) 到您的可执行文件中。在这两种情况下,您的可执行文件都不会“包含”您不使用的标准库的任何部分。

至于创建图书馆,这是一个有点复杂的话题,我将把它留给其他人,特别是因为根据你的问题的下一部分,我认为这不是你真正想做的事情。

头文件并不总是库的一部分。似乎您拥有的是多个源文件,并且您希望能够在另一个源文件中使用来自一个源文件的函数。您可以在不创建库的情况下做到这一点。您需要做的就是将您希望从其他地方访问的东西 foo.c 的 声明 放入 foo.h 中。声明是函数原型和“外部”变量声明之类的东西。例如,如果 foo.c 包含

int some_global;

void some_function(int a, char b)
 {
     /* Do some computation */
 }

然后为了使这些可以从其他源文件中访问,foo.h 需要包含

extern int some_global;

void some_function(int, char);

然后,你#include "foo.h" 在任何你想使用 some_global 或 some_function 的地方。由于标头可以包含其他标头,因此通常将标头包装在“包含守卫”中,这样​​声明就不会重复。例如, foo.h 应该是:

#ifndef FOO_H
#define FOO_H

extern int some_global;

void some_function(int, char);

#endif

这意味着每个编译单元(源文件)只会处理一次标头。

至于如何编译它们,切勿将 .h 文件放在编译器命令行上,因为它们不应包含任何可编译的代码(仅声明)。在大多数情况下,编译为完全没问题

cc main.c 1.c 2.c 3.c ... [etc]

但是,如果您有 50 个源文件,那么使用构建系统可能会更方便。在 Linux 上,这是一个 Makefile。在 Windows 上,这取决于您使用的开发环境。您可以在谷歌上搜索,或者在指定平台后提出另一个 SO 问题(因为这个问题已经很广泛了)。

构建系统的优点之一是它们独立编译每个源文件,然后将它们全部链接在一起,这样当您只更改一个源文件时,只需重新编译该文件(以及程序重新链接)而不是重新编译所有内容,包括未更改的内容。当您的程序变大时,这会产生很大的时间差异。

【讨论】:

  • 感谢您澄清这一点。这正是我需要的解释。
【解决方案2】:

您可以将多个 .c 文件合并到一个库中。这些库可以与其他 .c 文件链接以成为可执行文件。

您可以使用 makefile 来创建一个大项目。

makefile 有一套规则。每个规则都描述了创建一个程序片段所需的步骤以及它们与其他片段或源文件的依赖关系。

【讨论】:

    【解决方案3】:

    您需要创建一个共享库,标准库是在您的程序中隐式链接的共享库。

    拥有共享库后,您可以使用 .h 文件并使用 -lyourlib 编译程序,这对于 libc 来说是隐含的

    使用以下方法创建一个:

    gcc -shared test.c -o libtest.so
    

    然后像这样编译你的程序:

    gcc myprogram.c -ltest -o myprogram
    

    对于您的第二个问题,我建议您使用 Makefiles http://www.gnu.org/software/make/

    【讨论】:

      【解决方案4】:

      标准库已经编译并放置在您的机器上,准备好进行动态链接。这意味着库在程序需要时动态加载。将此与在您运行编译器/链接器时编译到您的程序中的静态库进行比较。

      这就是为什么您需要编译代码而不是标准库代码的原因。您可以自己构建一个动态(共享)库。

      作为参考,#include &lt;stdio.h&gt;导入标准库。它只允许编译和链接查看库的公共接口(了解使用了哪些函数、它们采用哪些参数、定义了哪些类型、它们的大小等)。

      Dynamic Loading

      Shared Library

      您可以将文件拆分为模块,并创建共享库。但通常随着项目变得越来越大,您往往需要更好的机制来构建您的程序(和库)。与其在需要进行重建时直接调用编译器,不如使用make 程序或像GNU Build System 这样的完整构建系统。

      【讨论】:

        【解决方案5】:

        如果您真的希望它像只包含一个 .h 文件一样简单,那么您的所有“库”代码都需要在 .h 文件中。但是,在这种情况下,有人只能将您的 .h 文件包含在一个且只有一个 .c 文件中。这可能没问题,具体取决于某人将如何使用您的“库”。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-01-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多