Undefinied Reference to...



  • Ich bekomme jedes mal beim compilieren diese Fehler

    C:\Users\White\AppData\Local\Temp/ccWz4PlV.o:notice.c:(.text+0x12f): undefined reference to `Notice:
    :Notice()'
    collect2: ld returned 1 exit status

    Ich bin noch relativer Anfänger und hab nun Stunden damit verbracht, rauszufinden was der Fehler heißt bzw. bedeuten mag und wie ich dagegen vorgehen kann, hab nun aber keine Lust mehr bzw. bin am verzweifeln und das hier ist mein letzter Anlauf diese Frage vllt erklärt zu bekommen.

    Der Code ist folgender:

    notice.c:

    #include <iostream>
    #include "Notice.class.h"
    
    using namespace std;
    
    int main() {
        Notice n;
    
        /*string command;
        getline(cin, command);
    
        if (command.substr(0, 3) == "add") {
            command = command.replace(0, 3, "");
    
            n->addNotice(command);
        } else if (command.substr(0, 4) == "done") {
            command = command.replace(0, 4, "");
    
            n->remove_notice(command);
        }
    
        cout << n->count_view() << " Notizen liegen noch vor" << endl;*/
    
        //delete n;
    }
    

    Notice.class.h

    #pragma once
    
    #include <time.h>
    #include <string.h>
    #include <vector>
    #include <stdio.h>
    
    using std::string;
    using std::vector;
    
    class Notice {
        public:
            Notice();
            bool addNotice(string notice);
            string getNotice(string match, int time_stamp = 0);
            vector<string> getNotice(int time_stamp = 0);
            bool remove_notice(string match, int time_stamp = 0);
            int count_view();
        private:
            bool _exist_notice(string match, int time_stamp = 0);
            bool _exist_file(string file);
            void _clear();
            void _create_date(char* &refer, int timestamp = 0);
            void _write_into(vector<string> output, int time_stamp = 0);
    
            char* _current_file;
            vector<string> _files;
    };
    

    Notice.class.c

    #include "Notice.class.h"
    
    Notice::Notice() {
        this->_create_date(this->_current_file);
    
        if (!this->_exist_file(this->_current_file)) {
            FILE* f = fopen(this->_current_file, "w+");
            fclose(f);
        }
    
        this->_clear();
    }
    
    void Notice::_create_date(char* &refer, int timestamp) {
        time_t cur_time = time(0);
        tm*    timer    = localtime(&cur_time);
    
        sprintf(
            refer,
            "%d-%d-%d.txt",
            timer->tm_mday,
            (timer->tm_mon + 1),
            (timer->tm_year + 1900)
        );
    }
    
    int Notice::count_view() {
        vector<string>::iterator it;
        int count = 0;
    
        while (it != this->_files.end()) {
            count++;
    
            it++;
        }
    
        return count;
    }
    
    bool Notice::addNotice(string notice) {
        if (!this->_exist_notice(notice)) {
            FILE* f = fopen(this->_current_file, "a");
            fputs(notice.c_str(), f);
            fclose(f);
    
            return true;
        }
    
        return false;
    }
    
    string getNotice(string match, int time_stamp) {
        int offset = 200;
        char* search;
    
        this->_create_date(search, time_stamp);
        if (time_stamp > 0 && !binary_search(this->_files.begin(), this->_files.end(), search)) {
            return null;
        }
    
        if (time_stamp <= 0) {
            search = this->_current_file;
        }
    
        if (!this->_file_exists(search)) {
            return null;
        }
    
        FILE* f = fopen(search, "r");
    
        char line[offset];
        while (!feof(f)) {
            fgets(line.c_str(), offset, f);
    
            if (strstr(match.c_str(), line)) {
                return line;
            }
        }
    
        fclose(f);
    
        return null;
    }
    
    vector<string> Notice::getNotice(int time_stamp) {
        int offset = 200;
        char* search;
    
        vector<string> output;
    
        output.reserve(20);
        output.resize(10);
    
        this->_create_date(search, time_stamp);
        if (time_stamp > 0 && !binary_search(this->_files.begin(), this->_files.end(), search)) {
            return null;
        }
    
        if (time_stamp <= 0) {
            search = this->_current_file;
        }
    
        if (!this->_file_exists(search)) {
            return null;
        }
    
        FILE* f = fopen(search, "r");
    
        char line[offset];
        int counter = 0;
        while (!feof(f)) {
            counter++;
    
            if (counter >= output.size()) {
                output.resize(output.size() + 10);
            }
    
            fgets(line.c_str(), offset, f);
    
            if (strlen(line)) {
                output.push_back(line);
            }
        }
    
        fclose(f);
    
        return output;
    }
    
    bool Notice::_exist_notice(string match, int time_stamp = 0) {
        string search = this->getNotice(match, time_stamp);
    
        return search == null ? false : true;
    }
    
    bool Notice::remove_notice(string match, int time_stamp) {
        vector<string> output = this->getNotice(time_stamp);
        vector<string>::iterator it;
    
        while (it != output.end()) {
            if (output[it].find(match)) {
                it = output.erase(it);
    
                this->_write_into(output, time_stamp);
    
                return true;
            }
    
            it++;
        }
    
        return false;
    }
    
    void Notice::_write_into(vector<string> output, int time_stamp) {
        char* search;
    
        if (time_stamp > 0) {
            this->_create_date(search, time_stamp);
        } else {
            search = this->_current_file;
        }
    
        if (!this->_file_exists(search)) {
            return null;
        }
    
        FILE* f = fopen(search, "w+");
    
        vector<string>::iterator it;
        while (it != output.end()) {
            fputs(output[it], f);
    
            it++;
        }
    
        fclose(f);
    }
    
    void Notice::_clear() {
        string sub = this->_current_file.substr(0, this->_current_file.find(".", 0));
        int last_day = timer->tm_mday;
    
        this->_files.resize(5);
        for (int i = 5; i > 0; i++) {
            last_day -= 1;
    
            string name = this->_current_file.replace(0, sub.length(), last_day);
    
            if (this->_exist_file(name)) {
                this->_files.push_back(name);
            }
        }
    
        vector<string>::iterator it;
    
        FILE* f;
        while (it != this->_files.end()) {
            char* line;
    
            f = fopen(this->_files[it], "r");
            fgets(line, 25, f);
    
            if (line.length() <= 0) {
                remove(this->_files[it]);
            }
    
            fclose(f);
    
            it++;
        }
    }
    
    bool Notice::_exist_file(string file) {
        //Schneller: nur Dateiinformationen lesen
        if (GetFileAttributes(file.c_str()) == INVALID_FILE_ATTRIBUTES) {
            return false;
        }
    
        return true;
    }
    


  • im Grunde bedeuted der Fehler, dass die Definition fehlt, die Deklaration aber vorhanden ist.
    Er findet die Implementierung des Konstruktors nicht.
    Versuch mal die Endung .cpp anstatt .c



  • Weiß Dein Compiler wo sich die gebrauchte Header Datei befindet?



  • XHansWurstX schrieb:

    Weiß Dein Compiler wo sich die gebrauchte Header Datei befindet?

    DAs hat doch mit der Fehlermeldung nichts zutun! Der Header wird gefunden, sonst hätte es geheißen, das er den Header nicht findet... logisch, oder?
    Außerdem ist es ein LINKER-Fehler und kein Präprozessor-Fehler.



  • XHansWurstX schrieb:

    Weiß Dein Compiler wo sich die gebrauchte Header Datei befindet?

    Am Header liegt es nicht, sonst würde ja schon die include-Anweisung fehlschlagen. Ihm fehlt die Implementierung, d.h. er deklariert im Header Funktionen, deren Definition nicht gefunden wird. Wurde ja schon gesagt...



  • naja die Notice.Class.h sollte in deinem fall direkt in deinem projektverzeichnis liegen...

    Bin mir aber nicht ganz sicher inwiefern das Ding zwei Punkte in Dateinamen akzeptiert. Sollte aber theoretisch funzen.



  • It0101 schrieb:

    naja die Notice.Class.h sollte in deinem fall direkt in deinem projektverzeichnis liegen...

    Bin mir aber nicht ganz sicher inwiefern das Ding zwei Punkte in Dateinamen akzeptiert. Sollte aber theoretisch funzen.

    Ich glaube, man kann jeden Scheiß im Dateinamen verwenden. Alles, was in Dateinamen halt so erlaubt ist. Du kannst ja auch Nicht-Header-Dateien inkludieren (.c, .cpp, .txt, .wasweissich)...



  • Nur das bei der Endung .c manche Compiler versuchen C zu kompilieren statt C++. Das gibt dann natürlich Probleme.



  • Hab ich nun mal geändert. Beide c Dateien sind nun cpp Dateien, doch wieder sowas:

    C:\Users\White\Desktop>g++ -o notice.exe notice.cpp
    C:\Users\White\AppData\Local\Temp/cc783PJK.o:notice.cpp:(.text+0x12f): undefined reference to `Notic
    e::Notice()'
    collect2: ld returned 1 exit status

    😕



  • wenn du es so kompilierst, ist ja klar.
    Du musst schon beide cpp Dateien angebenoO



  • JustAnotherNoob schrieb:

    wenn du es so kompilierst, ist ja klar.
    Du musst schon beide cpp Dateien angebenoO

    und das mache ich wie?

    g++ -o notice.exe notice.class.exe notice.cpp notice.class.cpp
    

    oder wie?
    wieso is das eigentlich wichtig, die wird doch per include eingelesen dachte ich.



  • Nein, inkludiert werden nur die Header-Dateien, die du in deinen Sourcen inkludierst. Und CPP-Dateien werden nicht inkludiert! Auch nicht im Source.

    CPP-Dateien sind sogenannte Übersetzungseinheiten. D.h. man übersetzt immer eine CPP-Datei für sich alleine. Aus jeder CPP-Datei wird eine OBJ-Datei (Object = übersetze Einheit). Am Ende werden alle OBJ-Dateien vom Linker zu einer EXE gelinkt (verbunden).

    So, d.h. der Linker sucht alle OBJ-Dateien zusammen und löst die übersetzten Referenzen (Funktionen, Klassen usw.) auf. Fehlt eine übersetzte Referenz, gibts einen Error. Und den hast du ja ebend erhalten.



  • Aso, wieder was gelernt 🙂
    Also muss ich jetzt beide cpp Dateien für sich compilieren oder wie?
    also

    g++ -o notice.exe notice.cpp
    
    g++ -o notice.class.exe notice.class.cpp
    


  • du willst ja nur eine .exe
    entweder so:
    g++ -onotice.exe notice.cpp notice.class.cpp
    oder so(Der Vorteil hierbei ist, dass man einzeln steuern kann was kompiliert wird und man dadurch Zeitspaart. Stichwort Gnu Make, oder ähnliche Buildsysteme):
    g++ -c notice.cpp
    g++ -c notice.class.cpp
    g++ -onotice.exe notice.o notice.class.o



  • Aso, wieder was gelernt
    Also muss ich jetzt beide cpp Dateien für sich compilieren oder wie?

    Dein Kommando war falsch, aber JustAnotherNoob hat es richtig gestellt. Du kannst natürlich auch alle CPP-Dateien in einem Rutsch mitgeben. Aber du mußt halt wissen, das der Compiler es am Ende halt trotzdem einzeln kompiliert.

    Aber eines wird dann deutlich:

    g++ -c notice.cpp 
    g++ -c notice.class.cpp
    

    Hier werden die Übersetzungseinheiten einzeln kompiliert und der Compiler erzeugt Objekt-Dateien. (da steht der kompilierte Code drin)
    Und dann können die Objekt-Dateien verlinkt werden:

    g++ -o notice.exe notice.o notice.class.o
    

    Folgendes ist natürlich nur eine kürzere Variante:

    g++ -o notice.exe notice.cpp notice.class.cpp
    

    Aber mit dem kompilieren einzelner Übersetzungseinheiten wird einem erstmal bewusst, wie eigentlich das CPP- und Header-Konzept funktioniert! Man geht immer von einer CPP-Datei aus, die nur Headers inkludiert.
    Die CPP-Datei ist also ein Modul, halt eine Einheit die für sich alleine besteht. Durch die Headers bekommt man nur eine schwache Abhängigkeit zu anderen Übersetzungseinheiten. Das ist wichtig, damit man keine starke Abhängigkeit zwischen Übersetzungseinheiten aufbaut - sonst ist das Modulkonzept nicht haltbar.



  • Gut vielen Dank für die Lektion 🙂


Anmelden zum Antworten