include语句的顺序在链接步骤中如何重要

How can the order of include statements matter in the linking step?

本文关键字:何重 链接 语句 顺序 include      更新时间:2023-10-16

我无法解释链接代码时看到的行为。也许有人知道发生了什么…

我有一个多文件C++项目,它使用GNU automake工具作为构建系统(全部在Linux上)。

在将源文件和头文件(称为util.ccutil.h)添加到项目中,并且已有一个源文件(calc.cc)从新添加的文件中调用函数后,我会收到一个链接错误,具体取决于include语句的出现位置。我重复一遍:错误发生在链接步骤,编译运行良好!!

示例:

在将新的include语句放在先前存在的语句的末尾时,我遇到了一个错误,例如:

calc.cc:

#include "file1.h"
#include "file2.h"
#include "file3.h"
#include "file4.h"
#include "util.h"   // new header

这个版本编译得很好。但是链接会产生错误(找不到符号)!!

现在,当将其更改为时

#include "util.h"   // new header
#include "file1.h"
#include "file2.h"
#include "file3.h"
#include "file4.h"

那么编译和链接运行良好!

由于链接器只读取.o文件,这一定意味着根据include语句的出现位置生成不同的内容。这怎么可能?

编译器是g++(GCC)4.4.6

util.h可能有一个#定义,它会更改其他文件之一的行为。

要想弄清楚到底发生了什么,最好的方法是检查这些头文件中缺少的符号的名称,从"工作"answers"非工作"方式编译calc.cc中获得预处理器输出,并比较这两个文件。

简单的头文件可以(重新)定义宏,这些宏可以更改以后宏的解释。

例如,在上面的示例中,如果file1.h执行

#define lseek lseek64

如果util.h有一个调用lseek的内联函数,那么根据包含顺序,生成的对象代码将具有对lseek或lseek64的符号引用。

这就是为什么项目倾向于首先包含config.h(由autoconf生成)的规则。

你绝对是对的:在这两种情况下会产生不同的对象代码。正如@hmjd还指出的,util.h中很可能有一个宏,其他(.h或.c)文件之一使用该宏,并且编译器假设任何未声明的、调用的标识符是一个函数——这很可能是这里的错误。