【问题标题】:Linker can't find a namespace's functions链接器找不到命名空间的函数
【发布时间】:2023-04-08 13:05:01
【问题描述】:

见下面的代码。它有问题,因为链接器抱怨它找不到Memory 的函数,但我不知道为什么。

memory.h

#pragma once
#include "includes.h" //it just includes other strandard headers.

class MemoryUnit
{
public:
    MemoryUnit() {}
    virtual int getValue() = 0;
    virtual int getSize() = 0;
    virtual void setValue(int) = 0;
    virtual ~MemoryUnit() {};
};
class Byte : public MemoryUnit
{
    int value;
public:
    static int size;
    Byte(int byte) :value(byte) {};
    int getSize() { return size; }
    int getValue() { return value; };
    void setValue(int byte) { value = byte; }
    ~Byte() {};
};
namespace Memory
{
    extern int size;
    extern MemoryUnit** map;
    void checkAddress(int address);
    int read(int adress);
    MemoryUnit* getOperation(int address);
    void write(int adress, MemoryUnit* data);
    void writeByte(int adress, int data);
}

memory.cpp

#include "includes.h"
#include "memory.h"
#include "simulator.h" // it contains only externed constants.

namespace Memory
{
    int size = 0;
    MemoryUnit** map = NULL;
    inline MemoryUnit* getOperation(int address)
    {
        return map[address];
    }
    inline void checkAddress(int address)
    {
        if (address < 0 || address >= MAX_MEMORY_SIZE)
            throw std::out_of_range("Invalid memory address.");
    }
    inline int read(int address)
    {
        checkAddress(address);
        return map[address]->getValue();
    }
    inline void write(int address, MemoryUnit* data)
    {
        checkAddress(address);
        delete map[address];
        map[address] = data;
    }
    inline void writeByte(int address, int data)
    {
        checkAddress(address);
        map[address]->setValue(data);
    }
}

类/命名空间memory.h 声明的任何地方都包含memory.h。下面的代码有什么问题吗?

编辑: 我正在使用 Visual Studio 2015。 我在构建项目时遇到的错误:

LNK1120 5 unresolved externals  simulator.exe
LNK2019 unresolved external symbol "void __cdecl Memory::writeByte(int,int)" referenced in function "void __cdecl ALU::setFlags(int)" alu.obj
LNK2001 unresolved external symbol "void __cdecl Memory::writeByte(int,int)" cu.obj
LNK2019 unresolved external symbol "class MemoryUnit * __cdecl Memory::getOperation(int)" referenced in function "void __cdecl CU::run(void)" cu.obj
LNK2001 unresolved external symbol "void __cdecl Memory::writeByte(int,int)" helpers.obj
LNK2019 unresolved external symbol "void __cdecl Memory::write(int,class MemoryUnit *)" referenced in function "void __cdecl readProgramCommands(void)" helpers.obj
LNK2001 unresolved external symbol "public: virtual int __thiscall MemoryPointer::getValue(void)" helpers.obj
LNK2001 unresolved external symbol "public: virtual int __thiscall IndirectMemoryPointer::getAddress(void)" helpers.obj
LNK2001 unresolved external symbol "void __cdecl Memory::writeByte(int,int)" main.obj

alu.halu.cpp 第一个错误:

//alu.h
#pragma once
#include "includes.h"
#include "operation.h"
namespace ALU
{
    int operation(Operation* op);
    void setFlags(int result);
}
//alu.cpp
#include "includes.h"
#include "simulator.h"
#include "alu.h"
#include "memory.h"
#include "operation.h"
namespace ALU
{
    int operation(Operation* operation)
    {
        // ...
        setFlags(result);
        return result;
    }
    inline void setFlags(int result)
    {
        Memory::writeByte(FLAG_Z, result == 0);
        // ...
    }
}

【问题讨论】:

  • 您能否提供确切的错误消息和产生错误的行?另外,您确定您也编译了 memory.cpp 并链接它吗?
  • @aybassiony 编辑了问题。所有文件都被编译,链接是 VS 的工作。

标签: c++ linker linker-errors unresolved-external


【解决方案1】:

您需要将内联函数定义放在头文件中(它们都必须出现在使用它们的每个翻译单元中),您可以将声明和定义分开,但两者都必须在头文件中。此外,它们必须声明为内联。

N4140 dcl.fct.spec 7.1.2.4

一个内联函数应该在它被使用的每个翻译单元中定义,并且应该有 在每种情况下都具有相同的定义(3.2)。 [注意:对内联函数的调用可能会在其调用之前遇到 定义出现在翻译单元中。 —尾注] 如果函数的定义出现在翻译中 单元在其第一次声明为内联之前,程序格式错误。

【讨论】:

    【解决方案2】:

    当您使用内联函数或方法时,它们的定义对于使用它们的每个源单元都应该是可见的。您在 Memory.cpp 中定义了内联函数,这就是为什么会出现“未解决”的链接器错误。

    要解决您的问题,您可以:

    1. 移除内联修饰符并将函数定义保留在 Memory.cpp 中。

    2. 保留内联修饰符,但将函数定义移动到 Memory.h。

    【讨论】:

    • 我会保留inline,因为它们应该尽可能快。但是除了getter/setter之外我还没有在头文件中写过,在头文件中定义移动更复杂的函数是个好主意吗?
    • 如果太复杂,编译器会忽略你的'inline'说明符。因此,如果性能是您的程序的主要因素,则将其保持内联不会造成伤害。
    猜你喜欢
    • 2015-10-31
    • 2012-12-16
    • 2019-07-16
    • 2017-04-11
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多