Linkerfehler



  • Ich habe eine Header-Datei namens main.h. In dieser deklariere ich einige Variablen und Strukturen. Diese Header-Datei include ich in mehreren anderen Dateien und dann kommt die Linkerfehlermeldung dass die Variablen und Strukturen bereits definiert sind.

    In main.h habe ich #pragma once angegeben.

    Die Variablen brauche ich aber in all diesen Dateien.

    Kann mir da wer helfen?

    P.S.: Code kommt bei Bedarf



  • Die erinnerung schrieb:

    P.S.: Code kommt bei Bedarf

    Bedarf besteht immer. Siehe http://www.c-plusplus.net/forum/304133

    Aber ich rate mal: Du definierst die Variablen anstatt sie nur zu deklarieren. Sagt Dir der Linker ja auch.



  • Das wäre main.h:

    #pragma once
    
    #include <iostream>
    #include <string>
    #include <ctime>
    #include <Windows.h>
    #include <locale>
    #include <fstream>
    #include <stdio.h>
    #include <bitset>
    #include <windowsx.h>
    #include <d3d9.h>
    #include <d3dx9.h>
    #include <vector>
    #include <utility>
    #include <algorithm>
    
    // include the Direct3D Library file
    #pragma comment (lib, "d3d9.lib")
    #pragma comment (lib, "d3dx9.lib")
    
    // define the screen resolution
    #define SCREEN_WIDTH		1280
    #define SCREEN_HEIGHT		1024
    #define FPS					100
    #define TEXTURES_PER_SIDE	64
    #define TEXTURE_SIZE		128
    #define NEAR_PLANE			0.01f
    #define FAR_PLANE			740.0f
    #define WAIT_TIME			100		//in Millisekunden
    #define CUSTOMFVF			(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
    
    struct CAMERA { D3DXVECTOR3 cam_pos, look_at, up_dir;
    CAMERA(float cam_pos_x, float cam_pos_y, float cam_pos_z, float look_at_x, float look_at_y, float look_at_z,
    	float up_dir_x, float up_dir_y, float up_dir_z)
    {
    	cam_pos.x = cam_pos_x;
    	cam_pos.y = cam_pos_y;
    	cam_pos.z = cam_pos_z;
    	look_at.x = look_at_x;
    	look_at.y = look_at_y;
    	look_at.z = look_at_z;
    	up_dir.x = up_dir_x;
    	up_dir.y = up_dir_y;
    	up_dir.z = up_dir_z;
    }
    
    CAMERA()
    {
    	cam_pos.x = 0.0f;
    	cam_pos.y = 0.0f;
    	cam_pos.z = 0.0f;
    	look_at.x = 0.0f;
    	look_at.y = 0.0f;
    	look_at.z = 0.0f;
    	up_dir.x = 0.0f;
    	up_dir.y = 0.0f;
    	up_dir.z = 0.0f;
    }
    };
    struct CUSTOMVERTEX {float X, Y, Z; D3DVECTOR NORMAL; float U, V;
    CUSTOMVERTEX(float X, float Y, float Z, float NORMAL_x, float NORMAL_y, float NORMAL_z, float U, float V)
    {
    	this->X = X;
    	this->Y = Y;
    	this->Z = Z;
    	this->NORMAL.x = NORMAL_x;
    	this->NORMAL.y = NORMAL_y;
    	this->NORMAL.z = NORMAL_z;
    	this->U = U;
    	this->V = V;
    }
    
    CUSTOMVERTEX()
    {
    	X = 0.0f;
    	Y = 0.0f;
    	Z = 0.0f;
    	NORMAL.x = 0.0f;
    	NORMAL.y = 0.0f;
    	NORMAL.z = 0.0f;
    	U = 0.0f;
    	V = 0.0f;
    }
    };
    
    typedef std::vector<CUSTOMVERTEX>::iterator vec_custom_it;
    typedef std::vector<short>::iterator vec_short_it;
    
    // global declarations
    LPDIRECT3D9 d3d;    // the pointer to our Direct3D interface
    LPDIRECT3DDEVICE9 d3ddev;    // the pointer to the device class
    LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL;    // the pointer to the vertex buffer
    LPDIRECT3DINDEXBUFFER9 i_buffer = NULL;
    LPDIRECT3DTEXTURE9 texture = NULL;    // our first texture
    CAMERA camera;		// camera
    const unsigned int fps = 1000 / FPS;
    const float texture_size = 1.0f / (float)(TEXTURES_PER_SIDE);
    const float texture_pixel = 1.0f / (float)(TEXTURES_PER_SIDE * TEXTURE_SIZE);
    bool state = false;
    int anz_vertices, anz_triangles;
    HWND hWnd;
    
    LPDIRECT3DVERTEXBUFFER9 v_buffer2 = NULL;    // the pointer to the vertex buffer
    LPDIRECT3DINDEXBUFFER9 i_buffer2 = NULL;
    int anz_vertices2, anz_triangles2;
    
    // function prototypes
    void initD3D(HWND hWnd);    // sets up and initializes Direct3D
    void render_frame(void);    // renders a single frame
    void cleanD3D(void);    // closes Direct3D and releases memory
    void init_graphics(void);    // 3D declarations
    void init_graphics2(void);
    void init_graphics3(void);
    void make_side(float x, float y, float z, unsigned int direction, std::vector<CUSTOMVERTEX>* vertices,
    	std::vector<short>* indices, unsigned short texture_id);		// makes a single side of a Cube
    void init_light(void);
    
    bool operator==(CUSTOMVERTEX left, CUSTOMVERTEX right);
    
    // the WindowProc function prototype
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    

    Den Variablen, denen ich Werte zuweisen, brauchen die auch.



  • Die One-Definition-Rule (ODR) sollte dir aber ein Begriff sein:
    also in Header-Dateien nur deklarieren (mittels "extern") und in genau einer Source-Datei definieren.

    Und ich hoffe, du weißt, daß globale Variablen böse sind.

    P.S. Und DirectX direkt mit C++ zu verwenden, führt nur zu schlechtem Code.
    Verwende dafür besser eine entsprechende Library, wie z.B. SFML.



  • Du willst also keine Hilfe. Bitte schließen.



  • Danke hat geholfen.



  • Was fehlt euch hier auf?

    - Nutzung von globalen Variablen anstelle von Konfigurationsobjekten
    - Konstaten als Präprozessor-Makros anstelle von const
    - Nicht Verwendung von Initalisierungsliste
    - #pragma once anstelle von Include guard

    Passt zwar nicht zum Problem 🙄



  • Zeus schrieb:

    Was fehlt euch hier auf?

    - Nutzung von globalen Variablen anstelle von Konfigurationsobjekten
    - Konstaten als Präprozessor-Makros anstelle von const
    - Nicht Verwendung von Initalisierungsliste
    - #pragma once anstelle von Include guard

    1. Konfigurationsobjekten sind mir unbekannt.
    2. Hier nehem ich die mit Absicht, weil die meiner Meinung nach besser sind. Welchen Vorteil haben deiner Meinung nach const s?
    3. Wo sollte ich den die Liste verwenden?
    4. Ist mir auch unbekannt



  • Die erinnerung schrieb:

    2. Hier nehem ich die mit Absicht, weil die meiner Meinung nach besser sind. Welchen Vorteil haben deiner Meinung nach const s

    In erster Linie Typsicherheit und man umgeht dabei die gängigen Probleme, die bei unachtsamer Verwendung des Präprozessors auftreten können. Welche das sind, sagt dir Google oder besser ein gutes Lehrbuch.

    Die erinnerung schrieb:

    3. Wo sollte ich den die Liste verwenden?

    Ist das jetzt dein Ernst? Du bist nich in der Lage die Verwendung von Initialisierungslisten im Kontext von C++-Konstruktoren nachzuschlagen, willst aber D3D-Code schreiben?

    Die erinnerung schrieb:

    4. Ist mir auch unbekannt

    Über die grundsätzliche Bedeutung der Präprozessor-Direktive "#pragma" bist du dir aber bewusst? Insbesondere darüber, dass ein Compiler nicht verpflichtet ist, die damit gegebenen Anweisungen zu kennen? Der übliche und überall funktionierende Weg das Einbinden eines Headers idempotent zu machen, sind Include-Guards:

    #ifndef PRAEPROZESSOR_SYMBOL
    #define PRAEPROZESSOR_SYMBOL
    <Inhalt des Headers>
    #endif
    

    Was könnte das wohl machen? Es gibt übrigens auch recht brauchbare kostenlose Ebooks, mit denen man Programmieren und C++ lernen kann. Da steht sowas alles drin.



  • Achso, das mit den Iclude Guards kannte ich. Aber ich verwende Mircosoft Visual C++ Express und ich weiß, dass der das richtig interpretiert.

    Und die eigentliche Bedeutung von #pragma ist mir nicht bekannt. ich habe bis her nur ein Anfängerbuch gelesen. Den Rest learning by doing. Von daher habe ich noch große Lücken.



  • Die erinnerung schrieb:

    Achso, das mit den Iclude Guards kannte ich. Aber ich verwende Mircosoft Visual C++ Express und ich weiß, dass der das richtig interpretiert.

    Kein Grund, nichtportablen Code zu schreiben. Viele Compiler können das zwar, aber viel Spaß, wenn du dann doch irgendwann deinen Code auf einen Compiler portieren möchtest, der das nicht unterstützt. Plötzlich darfst du dann ein paar tausend include-Guards nachreichen...

    Wenn du mit dem Anfängerbuch durch bist, steht als nächstes "Effective C++" von Scott Meyers an, der erklärt auch warum Makros pfui sind 🙂



  • Danke für den Buchtipp.

    Nur ich habe wirklich nicht vor (ich habe bis gerade eben nicht mal daran gedacht) den Compiler zu wechseln.

    Und falls doch, dann wäre das ja wohl mein Problem, oder?

    Aber hier würde ich sagen: Never change a running system.



  • Die erinnerung schrieb:

    Nur ich habe wirklich nicht vor [...] den Compiler zu wechseln.

    Noch 😉 Als Anfänger hat das niemand vor. War auch alleits nur ein gutgemeinter Ratschlag.

    Die erinnerung schrieb:

    Und falls doch, dann wäre das ja wohl mein Problem, oder?

    Das ist grundsätzlich alles, was du bei deinen ersten Gehversuchen in der Programmierung machst. Wie gesagt, nur ein gut gemeinter Ratschlag...

    Die erinnerung schrieb:

    Aber hier würde ich sagen: Never change a running system.

    Dann fix den Linkerfehler und ändere nichts mehr an dem Programm, sobald es läuft 😉



  • Ich bin sicher du weißt, was ich meine, falls nicht würde ich mir Sorgen machen. Aber danke für den Tipp, ich werde vielleicht darüber nachdenken, darüber nachzudenken ihn zu verwenden. 🤡 😃 🤡

    Nein, jetzt mal im Ernst:

    Wenns mir Probleme macht, dann ändere ich es.


Anmelden zum Antworten