c - 如何在函数文件和项目文件中正确包含自己的库

标签 c libraries kernighan-and-ritchie

我在尝试执行 Exercise 8-3 时遇到了困难K&R,练习的目标是重写stdio.h的一些函数例如fopen , fclose , fillbufflushbuf 这是我的源文件的组织方式:

stdio.h :包含类型和宏定义,以及库专有的一些函数的声明。文件的所有内容都包含在 #ifndef 之间#endif行如下:

#ifndef STDIO_H
#define STDIO_H
/* content of stdio.h */
#endif

myfunction.c : 我有一个 .c每个函数的文件,每个文件都有一个 #include "stdio.h"行加载所有需要的类型定义。

main.c : 我有代码来测试我的功能,main.c还有一个#include "stdio.h"行。

我的问题如下:当我尝试使用 gcc 编译所有文件时我遇到错误:

multiple definition of `_iob'

在我的每个函数文件中,我的 stdio.h包括在内,( _iob 是我只在 stdio.h 中定义的变量)...为什么会这样?我虽然#ifndef行是为了专门防止此类错误。

更一般地说:

  1. 您将如何制作自己的头文件和库/函数文件并在您的项目中使用它们?
  2. 有没有办法让链接器通过包含头文件来确定我的函数的位置,就像它对标准函数所做的一样?

最佳答案

请注意 library 之间的区别及其 header files .

库是二进制文件(的集合)machine code (带有一些额外的元数据,例如链接器的 relocation 指令)。

例如,在我的 Linux 系统上,动态库通常是共享对象(例如 /usr/lib/x86_64-linux-gnu/libgmp.so),尝试一些完全没有意义预处理器指令,如 #include "libgmp.so"//wrong

但是图书馆有一些API .该 API 由一些文档和一些头文件提供,例如gmp.h 并且您应该在使用它的任何 C 代码(您的 C 翻译单元)中#include "gmp.h"

myfunction.c: I have a .c file per function

每个函数都有一个文件通常很糟糕。您通常可以对相关功能进行分组。例如,在你的情况下,你可能想在同一个 myopenclose.c 翻译单元中定义你的 myfopenmyfclose 函数(即使你不必)因为这两个功能密切相关。根据经验,我更喜欢每个源文件只有一行或几千行(但这确实是个人喜好问题,有些人喜欢有很多小文件)。

请记住,编译器真正看到的是代码的预处理形式。考虑要求您的编译器生成该形式(例如,从 foo.c 您可以使用 gcc -C -E -Wall foo 获得其预处理形式 foo.i。 c > foo.i 在我的 Linux 桌面上)并查看它。在你自己的文件上尝试一下(例如你的 myopenclose.c 如果你有的话)。

如果您有许多小文件,编译器可能会在每个文件中包含相同的 header ,并且每次都会编译这些包含的声明。顺便说一句,请注意 gcc 只是一个驱动程序。将它与 -v 标志一起使用。您会看到它正在运行 cc1(正确的 C 编译器)、as(汇编器)、ld(链接器)等.

I run to the error:

multiple definition of `_iob'

on every one of my function files where my stdio.h is included, (_iob is a variable I only defined inside my stdio.h).

您可能应该在stdio.h声明 extern 您的 _iob 全局变量并定义 全局 _iob 仅在您的库的一个实现文件(可能是 myopenclose.c,如果相关的话)中。

不要混淆定义声明(变量、函数、类型等)。花一些时间阅读 C11标准n1570 .这些词在那里定义。根据经验,声明应该放在头文件 .h 中,定义(变量和函数)放在实现 .c 文件中(当然细节要复杂得多,您经常但不总是在头文件中定义类型和 struct

我强烈建议使用一些 Linux 发行版(它对开发人员和学生非常友好)并研究一些现有免费软件的源代码 C standard library (比如 musl-libc ,其代码可读性很强)。更一般地,研究现有的源代码 free software项目(例如 github )。他们会激励你。

Is there a way to make the linker figure out the position of my functions just by including the header file, the same way it does for standard functions ?

这说明了很多困惑(上面的问题没有任何意义)。阅读更多关于 compilers 的信息(您的 cc1 程序 - 由 gcc 启动 - 正在将 .c 文件翻译成一些 object file .o ) 和关于 linkers (您的 ld,通常由 gcc 启动,正在聚合多个目标文件,处理其中的重定位,并生成一个 ELF 库或一个可执行文件)。 preprocessing (例如 #include 指令)在编译时由 cc1 完成。链接器看不到任何头文件(它只处理目标文件或库)。

关于c - 如何在函数文件和项目文件中正确包含自己的库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47448659/

相关文章:

c - 在 C 中初始化 ADT

C编程比较二维数组的行和列

编译器需要在第一列添加 # 吗?

c - K&R 中边界有限的 qsort |排序过程不会在字符串中的下一个位置继续

c - 解释一下我的 C 代码的结果。 K&R "The C Prog language"Ex1-6

c - 在 C 中将字符串拆分为键值对

c - 什么时候在C中分配内存?

c - C中的库函数错误

java - 在 Eclipse Helios、Mac OSX 中将 Jars 添加到用户库

ios - iOS 的简化加密库