zoukankan      html  css  js  c++  java
  • 链接工作过程

    链接的作用是找到每个符号和函数的位置,并且将它们连接在一起。每个obj文件之间是没有联系的,这些文件实际上没法相互沟通,所以需要将他们连接到一个程序中来。即使程序只有一个cpp文件,程序入口主函数和一些其他的东西仍需要被链接。

    Math.cpp

    #include<iostream>
    
    void Log(const char* message)
    {
        std::cout<<message<<std::endl;
    }
    
    int Multiply(int a,int b)
    {
        Log("Multiply");
        return a*b;
    }

    如果按ctrl+F7进行编译,会编译成功,但是按F5进行build会报错:"entry point must be defined",因为缺少入口点main函数。

    程序的声称是经过编译和链接两个步骤的,如果去掉函数的大括号,编译时就会报错,error后面会有C表示错误来自编译,来自链接的错误在控制台中用LINK表示。

    unresolved external symbo(未解决的外部符号),当链接器找不到他需要的东西时就会这样报错。

    Log.cpp

    #include<iostream>
    
    void Logr(const char* message)
    {
        std::cout<<message<<std::endl;
    }

    Math.cpp

    #include<iostream>
    
    void Log(const char* message);
    
    int Multiply(int a,int b)
    {
        Log("Multiply");
        return a*b;
    }
    
    int  main()
    {
        std::cout<<Multiply(5,8)<<std::endl;
        std::cin.get();
    }

    在链接时就会出现这种错误,如果在Multiply函数中注释掉Log函数,那么不会报错,但是将main中的cout<<Multiply注释掉,还是会报错

    如果在Multiply中删掉,那么Log函数就成了彻底没有被使用的死代码了,但是第二种情况Log还是有可能被使用的,在其他的cpp文件中,所以Linker需要链接他。

    如果说明只在Math.cpp文件中使用Multiply函数,那么可以消除Link的必要。改变方法就是将Multiply函数设成静态

    #include<iostream>
    
    void Log(const char* message);
    
    static int Multiply(int a,int b)
    {
        Log("Multiply");
        return a*b;
    }
    
    int  main()
    {
        //std::cout<<Multiply(5,8)<<std::endl;
        std::cin.get();
    }

    这样连接时就不会报错

    当两个函数具有一样的名字,类型和返回值时,链接会出错,因为Linker不知道该链接哪个,将Math.cpp修改

    #include<iostream>
    
    void Log(const char* message);
    
    void Log(const char* message)
    {
        std::cout<<message<<std::endl;
    }
    
    static int Multiply(int a,int b)
    {
        Log("Multiply");
        return a*b;
    }
    
    int  main()
    {
        //std::cout<<Multiply(5,8)<<std::endl;
        std::cin.get();
    }

    此时链接就会出错,因为Log函数已经在Log.cpp中被定义了,这样会找到一个或多个被定义的符号。

    常见错误

    log.h

    #pragma once
    
    void Log(const char* message)
    {
        std::cout<<message<<std::endl;
    }

    Log.cpp

    #include<iostream>
    #include"Log.h"
    
    void InitLog()
    {
        Log("Initialized Log");
    }

    Math.cpp

    #include<iostream>
    #include"Log.h"
    
    static int Multiply(int a,int b)
    {
        Log("Multiply");
        return a*b;
    }
    
    int main()
    {
        std::cout<<Multiply(5,8)<<std::endll;
        std::cin.get();
    }

    链接时出现错误,说Log在Log.obj中已经定义,在代码中只有log.h定义了Log函数,为什么链接时会报错定义多次呢?

    因为在include时,头文件的内容会放到include语句的位置上,因此上述代码中,Log函数分别在Log.cpp和Math.cpp中定义了两次

    那么怎么解决呢?将log.h中的Log设置成静态

    #pragma once
    
    static void Log(const char* message)
    {
        std::cout<<message<<std::endl;
    }

    这意味着函数链接时链接只应该发生在文件内部,所以Math.cpp和Log.cpp都会有自己版本的Log函数,它对其他obj文件都是不可见的

    另一个改正方法是使用内联函数inline

    #pragma once
    
    inline void Log(const char* message)
    {
        std::cout<<message<<std::endl;
    }

    inline的意思是把函数的身体直接拿过来取代调用,在这种情况下,Log.cpp中代码相当于这样

    #include<iostream>
    #include"Log.h"
    
    void InitLog()
    {
        std::cout<<"Initialized Log"<<std::endl;
    }

    InitLog函数内部调用的Log函数直接变成了Log函数的结构。

    也可以改变Log函数的位置

    Log.h

    #pragma once
    
    inline void Log(const char* message);

    Log.cpp

    #include<iostream>
    #include"Log.h"
    
    void InitLog()
    {
        Log("Initialized Log");
    }
    
    void Log(const char* message)
    {
        std::cout<<message<<std::endl;
    }

    这样编译链接也不会报错

  • 相关阅读:
    [Linux/wine.笔记]关于WINE(Linux上运行Windows程序的兼容层)
    [docker.笔记]常用命令
    [技巧.DotNet]超级好用的动态对象ExpandoObject
    .net core 的窗体设计器进展(.NET Core Windows Forms designer),5月中旬或将发布成熟版!
    [问题记录.Oracle/odp.net]托管ODP中,连接池的连接验证参数(validate connection=true)无效?
    [JWT]Json Web Token 备忘
    [MQ]RabbitMQ的概要介绍及消息路由规则
    常见排序算法
    C语言数值存储溢出探讨
    从计算理解数组
  • 原文地址:https://www.cnblogs.com/wangtianning1223/p/12606240.html
Copyright © 2011-2022 走看看