C++:编译器和链接器功能

mad*_*adu 5 c++ compiler-construction linker

我想确切地了解程序编译器的哪个部分以及链接器所关注的内容.所以我写了下面的代码:

#include <iostream>
using namespace std;
#include <string>

class Test {
private:
    int i;

public:
    Test(int val) {i=val ;}
    void DefinedCorrectFunction(int val);
    void DefinedIncorrectFunction(int val);
    void NonDefinedFunction(int val);

    template <class paramType>
    void  FunctionTemplate (paramType val) { i = val }
};

void Test::DefinedCorrectFunction(int val)
{
    i = val;
}

void Test::DefinedIncorrectFunction(int val)
{
    i = val
}

void main()
{
    Test testObject(1);
    //testObject.NonDefinedFunction(2);
    //testObject.FunctionTemplate<int>(2);

}
Run Code Online (Sandbox Code Playgroud)

我有三个功能:

  • DefinedCorrectFunction - 这是正确声明和定义的普通函数.
  • DefinedIncorrectFunction - 此函数声明正确但实现错误(缺少;)
  • NonDefinedFunction - 仅声明.没有定义.
  • FunctionTemplate - 功能模板.

    现在如果我编译这段代码,我会在DefinedIncorrectFunction中找到缺少';'的编译器错误.
    假设我修复此问题然后注释掉testObject.NonDefinedFunction(2).现在我收到链接器错误.现在注释掉testObject.FunctionTemplate(2).现在我收到了缺少';'的编译器错误.

对于函数模板,我理解编译器不会触及它们,除非在代码中调用它们.所以缺少';' 在我调用testObject.FunctionTemplate(2)之前,编译器没有抱怨.

对于testObject.NonDefinedFunction(2),编译器没有抱怨,但链接器没有.据我所知,所有编译器都关心是知道这是一个声明的NonDefinedFunction函数.它并不关心实施.然后链接器抱怨,因为它无法找到实现.到现在为止还挺好.

我感到困惑的地方是编译器抱怨DefinedIncorrectFunction.它没有寻找NonDefinedFunction的实现,但是它经历了DefinedIncorrectFunction.

所以我不清楚编译器究竟做了什么以及链接器做了什么.我的理解是链接器链接组件与他们的调用.因此,当调用NonDefinedFunction时,它会查找NonDefinedFunction的编译实现并抱怨.但编译器并不关心NonDefinedFunction的实现,但是它确实用于DefinedIncorrectFunction.

如果有人可以解释或提供一些参考,我真的很感激.

谢谢.

Red*_*ron 5

编译器的功能是编译编写的代码并将其转换为目标文件.因此,如果您错过了;或使用了未定义的变量,编译器会抱怨,因为这些是语法错误.

如果编译顺利进行,则会生成目标文件.目标文件具有复杂的结构,但基本上包含五件事

  1. 标题 - 有关文件的信息
  2. 目标代码 - 机器语言代码(在大多数情况下,此代码不能单独运行)
  3. 重定位信息 - 实际执行时,代码的哪些部分需要更改地址
  4. 符号表 - 代码引用的符号.它们可以在代码中定义,从其他模块导入或由链接器定义
  5. 调试信息 - 由调试器使用

编译器编译代码并使用它遇到的每个符号填充符号表.符号指的是变量和函数.这个问题的答案解释了符号表.

它包含链接器可以处理到工作应用程序或共享库中的可执行代码和数据的集合.目标文件中有一个称为符号表的数据结构,它将目标文件中的不同项映射到链接器可以理解的名称.

需要注意的一点

如果从代码中调用函数,则编译器不会将例程的最终地址放在目标文件中.相反,它将占位符值放入代码中,并添加一个注释,告诉链接器在其处理的所有目标文件中查找各种符号表中的引用,并将最终位置放在那里.

生成的目标文件由链接器处理,链接器将填充符号表中的空白,将一个模块链接到另一个模块,最后给出可由加载器加载的可执行代码.

所以在你的具体情况下 -

  1. DefinedIncorrectFunction() - 编译器获取函数的定义并开始编译它以生成目标代码并在符号表中插入适当的引用.由于语法错误,编译失败,因此编译器因错误而中止.
  2. NonDefinedFunction() - 编译器获取声明但没有定义,因此它向符号表添加一个条目并标记链接器以添加适当的值(因为链接器将处理一堆目标文件,所以此定义可能存在于某些其他目标文件中).在您的情况下,您没有指定任何其他文件,因此链接器undefined reference to NonDefinedFunction因错误而中止,因为它无法找到对相关符号表条目的引用.

为了进一步理解它,可以说你的代码结构如下

File- try.h

#include<string>
#include<iostream>


class Test {
private:
    int i;

public:
    Test(int val) {i=val ;}
    void DefinedCorrectFunction(int val);
    void DefinedIncorrectFunction(int val);
    void NonDefinedFunction(int val);

    template <class paramType>
    void  FunctionTemplate (paramType val) { i = val; }
};
Run Code Online (Sandbox Code Playgroud)

文件try.cpp

#include "try.h"


void Test::DefinedCorrectFunction(int val)
{
    i = val;
}

void Test::DefinedIncorrectFunction(int val)
{
    i = val;
}

int main()
{

    Test testObject(1);
    testObject.NonDefinedFunction(2);
    //testObject.FunctionTemplate<int>(2);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

让我们首先只复制并组装代码但不链接它

$g++ -c try.cpp -o try.o
$
Run Code Online (Sandbox Code Playgroud)

该步骤没有任何问题.所以你在try.o中有目标代码.让我们尝试将其链接起来

$g++ try.o
try.o: In function `main':
try.cpp:(.text+0x52): undefined reference to `Test::NonDefinedFunction(int)'
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

你忘了定义Test :: NonDefinedFunction.我们在一个单独的文件中定义它.

File- try1.cpp

#include "try.h"

void Test::NonDefinedFunction(int val)
{
    i = val;
}
Run Code Online (Sandbox Code Playgroud)

让我们将其编译成目标代码

$ g++ -c try1.cpp -o try1.o
$
Run Code Online (Sandbox Code Playgroud)

它再次成功.让我们尝试仅链接此文件

$ g++ try1.o
/usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

没有主要因此赢得了't链接!!

现在,您有两个单独的对象代码,其中包含您需要的所有组件.只需将它们两个传递给链接器,然后让它完成剩下的工作

$ g++ try.o try1.o
$
Run Code Online (Sandbox Code Playgroud)

没错!这是因为链接器找到所有函数的定义(即使它分散在不同的目标文件中)并使用适当的值填充目标代码中的空白