草庐IT

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

coder 2024-02-06 原文

我想准确了解程序编译器查看的是哪个部分,链接器查看的是哪个部分。所以我写了下面的代码:

#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);

}

我有三个功能:

  • 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。

如果有人可以对此进行解释或提供一些引用,我将不胜感激。

谢谢。

最佳答案

编译器的作用是编译您编写的代码,并将其转换为目标文件。因此,如果您错过了 ; 或使用了 undefined variable ,编译器会报错,因为这些都是语法错误。

如果编译顺利进行,object files被生产。目标文件结构复杂但基本包含五样东西

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

编译器编译代码并用它遇到的每个符号填充符号表。符号指的是变量和函数。 This question的答案解释符号表。

This contains a collection of executable code and data that the linker can process into a working application or shared library. The object file has a data structure called a symbol table in it that maps the different items in the object file to names that the linker can understand.

注意事项

If you call a function from your code, the compiler doesn't put the final address of the routine in the object file. Instead, it puts a placeholder value into the code and adds a note that tells the linker to look up the reference in the various symbol tables from all the object files it's processing and stick the final location there.

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

所以在你的具体情况下 -

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

为了进一步理解它,假设您的代码结构如下

文件-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; }
};

文件 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;
}

让我们首先只编译和汇编代码但不链接它

$g++ -c try.cpp -o try.o
$

这一步没有任何问题。所以你在 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

您忘记定义 Test::NonDefinedFunction。让我们在一个单独的文件中定义它。

文件- try1.cpp

#include "try.h"

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

让我们把它编译成目标代码

$ g++ -c try1.cpp -o try1.o
$

再次成功。让我们尝试只链接这个文件

$ 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

没有主所以不会链接!!

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

$ g++ try.o try1.o
$

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

关于C++:编译器和链接器功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9529571/

有关C++:编译器和链接器功能的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  3. ruby-on-rails - Cucumber 是否只是 rspec 的包装器以帮助将测试组织成功能? - 2

    只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您

  4. ruby - Sinatra set cache_control to static files in public folder编译错误 - 2

    我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.

  5. ruby-on-rails - Prawn - 表格单元格内的链接 - 2

    我正在尝试用Prawn生成PDF。在我的PDF模板中,我有带单元格的表格。在其中一个单元格中,我有一个电子邮件地址:cell_email=pdf.make_cell(:content=>booking.user_email,:border_width=>0)我想让电子邮件链接到“mailto”链接。我知道我可以这样链接:pdf.formatted_text([{:text=>booking.user_email,:link=>"mailto:#{booking.user_email}"}])但是将这两行组合起来(将格式化文本作为内容)不起作用:cell_email=pdf.make_c

  6. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  7. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  8. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  9. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  10. ruby-on-rails - rails 功能测试 - 2

    在Rails自动生成的功能测试(test/functional/products_controller_test.rb)中,我看到以下代码:classProductsControllerTest我的问题是:方法调用products()在哪里/如何定义?products(:one)到底是什么意思?看代码,大概意思是“创建一个产品”,但是它是如何工作的呢?注意我是Ruby/Rails的新手,如果这些是微不足道的问题,我深表歉意。 最佳答案 如果您查看test/fixtures文件夹,您会看到一个products.yml文件。这是在您创建

随机推荐