静态库不需要头文件?

Uhl*_*hlo 0 c linux linker gcc

我是C的新手,尤其是编写静态库,我的库中出现了奇怪的行为.

我写了一个名为cde的静态库.我用gcc将不同的部分编译成.o文件,然后我用ar将它们全部放在一个.a文件中

现在,当我想测试我的库时,我会执行以下操作:

gcc test.c -L../bin -lcde -lelf

libcde.a是我的库,位于../bin.libelf.a是我的库所需的库(我不知道如何将它直接放入我自己的库中......).

问题是我可以调用我的库的每个函数,不必包含我的库的头文件.怎么可能?在编译时,文件不应该链接,因此编译器应该不知道我的库中有哪些函数可用...

当我按以下方式运行时,

gcc -L../bin -lcde -lelf test.c

文件test.c找不到我的头文件中定义的任何函数,即使我已经包含它.

我想我在这里做了一些根本性的错误,但我真的找不到什么.

Eri*_*hil 8

这里有两个问题:

  1. 为什么test.c编译时没有提供库中例程声明的头文件?
  2. 为什么链接test.c首先在命令行中test.c列出,但在命令行中没有列出?

我们无法提供第一个完整的答案,因为您没有显示源代码.正如其他人所指出的那样,C有一些余地提供隐含声明,主要是出于历史原因.这些隐式声明可能与您的例程的实际定义不匹配,这可能会导致错误,因此您应该避免隐式声明.

你的第二个问题的答案就是这个.给定您显示的两个命令行之一,编译器将编译test.c然后调用链接器.(编译器也可以做其他事情,例如编译而不链接或链接来自先前编译的源的对象模块.)当编译器调用链接器时,它按照与您的顺序对应的顺序传递链接器参数将它们传递给链接器.特别是,如果你把-lcde之前test.c,那么编译器把-lcde那个来自对象模块之前test.c,test.o当它运行的链接.

这很重要,因为链接器的运行方式.除此之外,链接器还有一个需要定义的符号列表.该列表最初为空.链接器从左到右处理命令行的输入.当链接器test.o在其命令行中看到对象模块时,它会读取对象模块并对其进行处理.通常,对象模块包含对未定义的某些符号的引用,例如对库例程的调用.如果链接器已经从先前文件中定义了这些符号,则它会将引用连接到定义.如果它没有定义,则将符号添加到链接器需要定义的符号列表中.

当链接器处理库文件时,它会检查库中的每个对象模块,以查看该对象模块是否定义了链接器所需定义列表中的符号.如果是,则链接器读取该对象模块并将其(及其定义)添加到链接器正在构建的可执行文件中.如果不是,链接器将忽略该对象模块.

现在我们可以看到为什么test.c -lcde有效,但却-lcde test.c没有.在前一种情况下,链接器会列出所需的所有内容test.o,然后从cde库中获取这些内容.在后一种情况下,链接器会看到cde库,但是它还不需要任何东西,所以它继续而不从库中取任何东西.然后链接器读取test.c并添加到所需符号列表中.然后命令行结束,链接器没有更多文件,但仍然没有定义的符号.所以它报告错误.

因此,通常,库应该在命令行中列出最后.


nos*_*nos 5

如果没有头文件,您将没有函数的原型。这不是一个错误,但是 C 编译器会假定您调用的函数的原型,而编译器尚未看到该函数的原型

 int functionname()
Run Code Online (Sandbox Code Playgroud)

空 () 意味着类似“任何参数”,因此传递给该函数的任何参数都将被调用。

根据参数的实际类型以及函数的返回值,这可能会恰到好处,或者至少在某些情况下看起来可行。

在链接阶段,当您生成可执行文件时,链接器将仅链接到函数名称。如果您调用名为“foo”的函数,并且您的库也有一个名为“foo”的函数符号,则链接器会选择该函数符号。