linker link 对象文件本身吗?

Does linker link an object file with itself?

根据我在其他 SO 答案中读到的内容,例如 this and this,编译器将源代码转换为目标文件。目标文件可能包含对 printf 等函数的引用,需要 linker.

解析

我不明白的是,当声明和定义都存在于同一个文件中时,如下例,编译器或linker 是否解析对[=13 的引用=]?

或者这只是编译器优化的一部分?

int return1();

int return2() {
  int b = return1();
  return b + 1;
}

int return1() {
  return 1;
}

int main() {
  int b = return2();
}

我已经通过运行g++ -E main.cpp.[=确保预处理与此无关17=]


更新2020-7-22

答案都很有帮助!谢谢!

从下面的答案来看,在我看来,编译器可能会也可能不会解析对 return1 的引用。但是,我还是不清楚如果只有一个翻译单元,就像我给的例子,如果编译器没有解析它,这是否意味着linker 必须解决吗?

因为在我看来 linker 将 link 多个(大于一个) 对象文件放在一起,如果只有一个翻译单元(目标文件),link则需要link目标自己归档,我说得对吗?

还有什么办法可以确定我的电脑上是哪一种情况?

视情况而定。这两个选项都是可能的,您没有提到的选项也是可能的,例如编译器或链接器重新排列代码,以便 none 的函数不再存在。将编译器发出对函数的引用和链接器解析这些引用作为理解 C++ 的一种方式很好,但请记住,编译器和链接器所要做的就是生成一个工作程序,并且有许多不同的方法可以做到这一点。

然而,编译器和链接器必须做的一件事是确保对标准库函数的任何调用发生(如您提到的 printf),并按照 C++ 源指定的顺序发生。除此之外(以及其他一些类似的担忧)他们或多或少可以随心所欲。

[lex.phases]/1.9,涵盖翻译的最后 阶段 ,指出 [强调 我的]:

All external entity references are resolved. Library components are linked to satisfy external references to entities not defined in the current translation. All such translator output is collected into a program image which contains information needed for execution in its execution environment.

但是,由编译器决定库组件是单个翻译单元还是它们的组合;由 [lex.separate]/2 [强调 我的]:

[ Note: Previously translated translation units and instantiation units can be preserved individually or in libraries. The separate translation units of a program communicate ([basic.link]) by (for example) calls to functions whose identifiers have external linkage, manipulation of objects whose identifiers have external linkage, or manipulation of data files. Translation units can be separately translated and then later linked to produce an executable program.  — end note ]


OP: [...] does compiler or linker resolve the reference to return1?

因此,即使 return1 具有外部链接,因为它在引用它的翻译单元中定义(在 return2 中),链接器也不应该 需要to 解析对它的引用,因为它的定义存在于当前翻译中。然而,标准段落(可能是故意的)对于何时需要链接以满足外部引用的要求有点模糊,我不认为它是一个不合规的实现来推迟解析对 [=10= 的引用] 在 return2 直到链接阶段。

实际上,问题在于以下代码:

static int return1();

int return2() {
  int b = return1();
  return b + 1;
}

int return1() {
  return 1;
}

链接器的问题是现在每个翻译单元都可以包含自己的 return1,因此链接器在选择正确的 return1 时会遇到问题。有一些技巧,例如将翻译单元名称添加到函数名称中。大多数 ABI 不这样做,但 C++ 标准允许这样做。然而,对于匿名名称空间,即 namespace { int function1(); },ABI 将使用此类技巧。