Fazal Mahmud Niloy
Fazal Mahmud Niloy

Reputation: 103

Getting "error LNK2019: unresolved external symbol referenced in function _main" on VScode

I was practising a LinkedList implementation in Visual Studio and the code runs fine in Visual Studio. But since I use vscode most of the time I followed this tutorial from official vscode website. the demo code form the given link builds and runs successfully without any error or warning. but when I try to build my LinkedList c++ project I get errors for each function and the build exits. The errors are given below

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

I don't actually know where I am making the mistake since this is the first time I am trying to run C++ codes on VScode. my CPP, header and Driver files are given below.

List.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

List.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();
}

It would be great if someone could point out where I am making the mistake. I don't really want to open heavy apps like Visual Studio to practice my codes. TIA.

Upvotes: 0

Views: 7208

Answers (2)

Nolca
Nolca

Reputation: 45

Link the lost libs after #include (beware #pragma only in msvc, gcc would get error)

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "xxx.lib")
...
  1. Search the specific function in error, I get <winuser.h>
  2. ask for GPT, I get user32.lib

Upvotes: 0

Lala5th
Lala5th

Reputation: 1163

As neither of the current "Answers" are applicable (One is wrong and the other is very bad practice leading to similar errors later on), here is a solution.

Disclaimer: I generally use CMake to create the builds for me meaning I am unfamiliar as to how to do this in VSCode, so this is an unoptimal way of doing it. (The reason is that in this solution all files are compiled at the same time, meaning that any time you change any file, you have to recompile all files, rather than recompiling the changed file and linking again.)

If you have all files in a dir like:

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

Then you can use:

{
  "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
      }
    }
  ]
}

And that should in theory work.

Example as to what the error is:

Lets say you have:

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

Now the compiler is given the task of converting A.cpp into "machine code". First it executes preprocessor directives (in this case pasiting the contents of B.h to the top of A.cpp) converting A.cpp to:

void addOne(int&);

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

And after this it compiles it. The compiler doesn't know what addOne does. All it knows is what it looks like (takes one int& argument and returns void). After the compiler is finished generating the "machine code", the linker takes control, which gets the task: Put everything together so that it makes sense. The "machine code" does not have all the things it needs to run, so the linker resolves references (i.e. it sees that you pass it two of the object files (generated by the compiler). One references void addOne(int&), but never implements it, and the other merely implements it.). It then packages them into an executable, that you can run.

The reason why there are unresolved references is because List.cpp is not compiled, and not passed to the linker, therefore it can not find how to run functions declared in List.cpp.

Note if you want to go with #include "List.cpp" "solution" you can, BUT then it would be beneficial to declare everything in List.cpp to have static linkage, otherwise you might have the opposite error later (i.e. multiple definitions of the same thing).

Upvotes: 2

Related Questions