Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Anonymous

unregistriert

1

21.02.2004, 00:25

Allg. Frage zu globalen Variablen und Programmstruktur

Hallo,

ich habe eine mehr allgemein gehaltene Frage zur Struktur und zum Aufbau eines Programmes.
Ich würde gerne eine Sammlung von Funktoinen und Klassen (wie z.B. eine Grafik Engine) in ein "fremdes" Programm einbinden, nur indem ich 1 Header Datei einbinde - mit der einen Header Datei sollen also alle Funktionen zur Verfügung stehen.
Diese eine Header soll dann alle weiteren Header Dateien, die meine "Engine" benötigt, einbinden. In der Header DAtei sollen
ausserdem die Protortypen verschiedener Funktionen stehen, sowie globale Variablen deklariert sein.
Und genau der letzte Punkt ist mein Problem, denn wenn ich versuche, dort eine globale Variable zu deklarieren, erscheint dieser Fehler:

IncludeTest error LNK2005: "int GlobaleVariable" (?GlobaleVariable@@3HA) bereits in main.obj definiert

Es kommt mir so vor, als versuche der Compiler mehrmals (durch das mehrfache einbinden von mainheader.h in weiteren cpp Dateien) die globales Variablen zu deklarieren, obwohl ich das Mehrfachkompilieren durch #ifndef verhindert habe.

Hier einmal kurz die Struktur, falls meine Erklärung unverständlich sein sollte:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
main.cpp
   |
   `- mainheader.h
         |
         +- header1.h
         |
         +- header2.h
         |
         +- header3.h
         |
         `- globale Variablen und versch. Funktionen (Prototypen)
         
zweitedatei.cpp
   |
   `- mainheader.h
         |
         `....
         
drittedatei.cpp
   |
   `- mainheader.h
         |
         `....


Kurze Erklärung:
meinheader.h : die einzige Header Datei, die ein "fremdes" Programm einbinden muss
In der zweitedatei.cpp und drittedatei.cpp wird diese mainheader.h wieder eingebunden, um dort ebenfalls die Funktionen zur Verfügung zu stellen.



Falls mein Vorhaben bzw. die Art und Weise, wie ich z.B. eine globale Variable anlegen möchte, völliger Unsinn ist, dann bitte ich Euch mich zurechtzuweisen :-)

Über Hilfe würde ich mich sehr freuen


MfG,
Timo

2

21.02.2004, 01:03

Der Compiler erstellt deine Globalen Varialben nur einmal pro Modul (CPP - Code file). In deinem Projekt (z.B. deine EXE-file) sind aber mehrere Module und jedes dieser Module hat deine Globalen Variablen. Und genau das darf nicht sein. Die Module werden zwar alle einzeln Compilert aber nicht einzeln gelinkt. Der Linker sieht alles Globaler. Wenn er also in allen Modulen die Variable int g_ID findet, weis er nicht welche er nehmen soll. Oder besser gesagt, er hat schon eine genommen. Die erste die er erwischt hat.

Man kann dieses Problem umgehen, in dem man das Schlüsselwort "extern" verwendet. Man Definiet hier eine Globale Variable in einem Modul und Deklariert dann mittels "extern" die gleich Variable in einer Header. Dann weis der Linker das er die Globale Variable aus dem Modul nehmen soll wo sie Definiert ist.
Das Schlüsselwort "extern" Funktioniert übrigends nicht mit Globalen Variablen die in einer DLL liegen. Diese müssen wie Funktionen oder Klassen exportiert werden.

Dies ist aber keine besonders schöne Lösung. Generell sollte man in einem Projekt, das vor allem dafür bestimmt ist in anderen Projekt eingefügt zu werden, keine Globalen Variablen verwenden.

[edit]Wenn du keine Lust hast dein fertiges Projekt (das du einfügen willst) nicht komplett umschreiben willst. Kannst du auch den Präprozessor dafür missbrauchen. Etwa so:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// IN DER HEADER
#ifndef DEFINE_GLOBALES
#define EXTERN extern
#else
#define EXTERN
#endif

// Globale Variablen
EXTERN int g_ID;


// IN EINER CPP DATEI (Z.B. main.cpp)
#define DEFINE_GLOBALES
#include "header.h"
....

// IN ALLEN ANDEREN CPP DATEIEN
#include "header.h"
Damit ist das Problem ebenfalls gelöst.
Wichtig! Ich übernehme keinerlei Verantwortung für eventl. Datenverlust oder Schäden am Rechner ;D

3

21.02.2004, 14:11

Nur so am Rande: Beim Visual-Studio (und vielleicht auch bei anderen Compilern) kannste mehrfache Kompilation von headern durch das Schlüsselwort pragma once ausschalten.

Anonymous

unregistriert

4

22.02.2004, 00:02

Vielen dank für die Antworten.

Generell will ich auch keine globalen Variablen einsetzen, jedoch wollte ich für Dinge, die garantiert nur einmal vorhanden sind, solche Variablen verwenden. Da wären z.B. das Handle zu dem Fenster einer DirectX Anwendung, es gibt ja meistens nur ein Fenster, oder auch die Variable zum Direct3D Interface (PDIRECT3D9).

Mein Problem ist, ich habe eine Funktion namens "Shutdown()", welche solche (globalen) Variablen bzw. die Objekte die dahinter stehen, zerstören soll, damit also der Speicher aufgeräumt wird. Müsste ich der Funktion erst jede Variable, welche aufgeräumt werden soll, erst übergeben, hätte es ja wenig Sinn.

Ich richte meinen Blick da auch sehr auf die TriBase Engine, welche ja die Variablen g_pD3D und auch eine globale Variable für das D3D Interface benutzt. Wie wurden diese globalen Variablen denn in dem Programm implementiert?

Vielen Dank nochmals

Timo

5

23.02.2004, 17:37

Zitat von »"Pirat!"«

Nur so am Rande: Beim Visual-Studio (und vielleicht auch bei anderen Compilern) kannste mehrfache Kompilation von headern durch das Schlüsselwort pragma once ausschalten.
Es geht hier nicht um die mehrfache Kompilation sondern um das mehrfache verlinken von gleichen Symbolen im gleichen Namensraum (hier der Globale).

Globale Variablen kann man auch sehr schön durch ein geschicktes Klassen Design verhindern. Ich habe mir z.B. einen Adapter geschrieben, der mir das D3D8 Interface kapselt. Das IDirect3DDevice8 Interface ist da als private statische Membervariable Deklariert. Der Zugriff erfolgt über eine Inline Funktion. Wenn der Adapter erzeugt wird, wird alles schön Enumeriert dann erstellt man ein D3D Device fertig. Wenn der Adapter gelöscht wird, wird auch das D3D Device freigegeben. So habe ich die Globalen Variablen umgangen. Meine Adapter findest du auf meiner Seite Dragon-Master.net
Wichtig! Ich übernehme keinerlei Verantwortung für eventl. Datenverlust oder Schäden am Rechner ;D

Werbeanzeige