在 VScode 上收到“错误 LNK2019:函数 _main 中引用了无法解析的外部符号”

问题描述 投票:0回答:2

我正在 Visual Studio 中练习 LinkedList 实现,代码在 Visual Studio 中运行良好。但由于我大部分时间都使用 vscode,所以我遵循了 来自 vscode 官方网站的教程。给定链接中的演示代码构建并成功运行,没有任何错误或警告。但是当我尝试构建 LinkedList c++ 项目时,每个函数都会出现错误,并且构建退出。错误如下

LinkedList.obj : error LNK2019: unresolved external symbol "public: __thiscall 

List::List(void)" (??0List@@QAE@XZ) referenced in function _main
LinkedList.obj : error LNK2019: unresolved external symbol "public: void __thiscall List::addNode(int)" (?addNode@List@@QAEXH@Z) referenced in function _main
LinkedList.obj : error LNK2019: unresolved external symbol "public: void __thiscall List::deleteNode(int)" (?deleteNode@List@@QAEXH@Z) referenced in function _main
LinkedList.obj : error LNK2019: unresolved external symbol "public: void __thiscall List::printList(void)" (?printList@List@@QAEXXZ) referenced in function _main

我实际上不知道我在哪里犯了错误,因为这是我第一次尝试在 VScode 上运行 C++ 代码。下面给出了我的 CPP、头文件和驱动程序文件。

列表.h

#ifndef LIST_H
#define LIST_H

class List {
private:
    typedef struct node {
        int data;
        node* next;
    }*nodePtr;

    nodePtr head;
    nodePtr current;
    nodePtr temp;

public:
    List();
    void addNode(int addData);
    void deleteNode(int delData);
    void printList();
};

#endif

列表.cpp

#include <iostream>
#include <cstdlib>

#include "List.h"

using namespace std;

List::List() {
    head = NULL;
    current = NULL;
    temp = NULL;
}

void List::addNode(int addData) {
    nodePtr n = new node;
    n->next = NULL;
    n->data = addData;

    if (head != NULL) {
        current = head;

        while (current->next != NULL) {
            current = current->next;
        }
        current->next = n;
    }

    else head = n;
}
void List::deleteNode(int delData) {
    nodePtr delPtr = NULL;
    temp = head;
    current = head;

    while (current != NULL && current->data != delData) {
        temp = current;
        current = current->next;
    }

    if (current == NULL) {
        cout << delData << " not found.\n";
        delete delPtr;
    }

    /**/
    else {
        delPtr = current;
        current = current->next;
        temp->next = current;
        if (delPtr == head) {
            head = head->next;
        }
        delete delPtr;
        cout << delData << " was deleted.\n";
    }
}

void List::printList() {
    if (head == NULL) {
        cout << "list is empty";
    }

    else {
        current = head;
        while (current != NULL) {
            cout << current->data << endl;
            current = current->next;
        }
    }
}

LinkedList.cpp

#include <cstdlib>
#include "List.h"
#include <iostream>

int main() {
    List demo;
    demo.addNode(6);
    demo.addNode(12);
    demo.addNode(45);
    demo.addNode(67);
    demo.printList();

    demo.deleteNode(6);
    demo.deleteNode(12);
    demo.printList();
}

如果有人能指出我在哪里犯了错误,那就太好了。我真的不想打开像 Visual Studio 这样的重型应用程序来练习我的代码。短暂性脑缺血发作。

c++ visual-studio-code
2个回答
2
投票

由于当前的“答案”都不适用(一个是错误的,另一个是非常糟糕的做法,导致以后出现类似的错误),这里有一个解决方案。

免责声明:我通常使用 CMake 为我创建构建,这意味着我不熟悉如何在 VSCode 中执行此操作,因此这是一种不是最佳的方法。 (原因是在这个解决方案中,所有文件都是同时编译的,这意味着每当您更改任何文件时,都必须重新编译所有文件,而不是重新编译更改的文件并再次链接。)

如果您的目录中有所有文件,例如:

project_root/
- List.h
- List.cpp
- LinkedList.cpp

然后你可以使用:

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "label": "cl.exe build active file",
      "command": "cl.exe",
      "args": [
        "/Zi",
        "/EHsc",
        "/Fe:",
        "${fileDirname}\\${fileBasenameNoExtension}.exe",
        "project_root/*.cpp"
      ],
      "problemMatcher": ["$msCompile"],
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}

理论上这应该可行。

错误的示例:

假设你有:

----------------  B.h  ---------------------
// Omitted ifndef guard
void addOne(int&);
---------------- B.cpp ---------------------
void addOne(int& addTo){
    ++addTo;
}
---------------- A.cpp ---------------------
#include "B.h"

int main(){
    int a = 0;
    addOne(a);
    return a;
}

现在编译器的任务是将

A.cpp
转换为“机器代码”。首先,它执行预处理器指令(在本例中将
B.h
的内容粘贴到
A.cpp
的顶部)将
A.cpp
转换为:

void addOne(int&);

void main(){
    int a = 0;
    addOne(a);
    return a;
}

之后它会编译它。编译器不知道

addOne
的作用。它只知道它的样子(接受一个
int&
参数并返回
void
)。编译器完成生成“机器代码”后,链接器接管控制权,其任务是:将所有内容放在一起,使其有意义。 “机器代码”没有运行所需的所有内容,因此链接器解析引用(即,它看到您向其传递了两个目标文件(由编译器生成)。其中一个引用
void addOne(int&)
,但从未实现它,而另一个只是实现它。)。然后它将它们打包成一个可执行文件,您可以运行它。

存在未解析的引用的原因是因为

List.cpp
未编译,并且未传递给链接器,因此无法找到如何运行
List.cpp
中声明的函数。

请注意,如果您想使用

#include "List.cpp"
“解决方案”,您可以,但是在
List.cpp
中声明所有内容以具有
static
链接将是有益的,否则稍后您可能会遇到相反的错误(即多个定义同样的事情)。


0
投票

这里有一些非常简单但详细的中文解决方案:

https://zhuanlan.zhihu.com/p/352148624

我的解决方案:

#include
之后链接丢失的库(注意
#pragma
仅在msvc中,gcc会出错)

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "xxx.lib")
...
  1. 搜索错误的具体函数,我得到
    <winuser.h>
  2. 要求 GPT,我得到
    user32.lib
© www.soinside.com 2019 - 2024. All rights reserved.