Linker Problem

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Linker Problem

Beitrag von starcow »

Guten Morgen Zusammen

Irgendwie krieg ich mein Programm nicht mehr kompiliert. Der Compiler beschwert sich über fehlende Definitionen.
Ich weiss echt nicht mehr weiter, weil ich sehe nicht, was da fehlen könnte.

Ein wesentlicher Teil des Programms sind Klassenfunktionen, die an der entsprechenden Stelle aufgerufen werden.
Also hatte ich das Projekt bis jetzt so organisiert, dass jede Klasse aus zwei Dateien besteht. Einem Header und einem "Body". Im Header steht die Deklaration der entsprechenden Klasse und im "Body" wird dann als erstes der Header inkludiert.

Die Klassen sind halt eng miteinander verknüpft, da sie Teils Zeiger auf andere Klassen benötigen. Eigentlich nicht schwer nachzuvollziehen.
Wenn eine Klasse von einer anderen wissen musste, habe ich einfach im entsprechenden Header den jeweils anderen Header eingebunden.
Irgendwann - aus mir nicht nachvollziehbaren Gründen - hat sich dann der Compiler trotzdem beschwert, dass er eine Deklaration einer Klasse nicht kenne. Ich bin dann dazu übergegangen, systematisch von jeder Klasse eine Vorwärtsdeklartion aufzuführen.
Irgendwie musste ich ja mal mit der Deklaration einer Klasse beginnen. Also eigentlich die Stelle, an der sich die Katze in den Schwanz beisst.

Als dann erneut Linker-Fehler auftraten, habe ich versucht, einfach alle Vorwärtsdeklarationen und alle "Klassen-Köpfe" in ein einzelnes File zu packen und bei den Klassen selbst nur noch dieses eine Header-File einzubinden. Das geht aber auch nicht, wie ich grad feststellen muss - und ich verstehe nicht wieso. Alle Klassen sind vorwärts deklariert. Alle Klassen kennen _alle_ "Klassenköpfe". Auch Visual Studio erkennt die Klassen korrekt (grün).

Ich meine, ich könnte noch versuchen, einfach sämtliche Klassen in ein einzelnes File zu packen. Dann kann ich aber gleich dazu übergehen, mit einer einzelnen Datei zu arbeiten.

Irgendwie verstehe ich nicht, wie dass gemeint ist - und wie man das ganze sinnvoll aufgleist ohne komplexe including-gard Methoden.

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Hannes
Beiträge: 36
Registriert: 11.06.2008, 06:04

Re: Linker Problem

Beitrag von Hannes »

Ohne die Fehlermeldung zu kennen kann ich zwar nur raten, aber zirkuläre abhängigkeiten könnten das Problem sein.

Schreib mal bitte die Fehlermeldung und noch eine Beispielklasse mit beispiel.h und beispiel.c, um zu sehen wie du konkret vorgegangen bist.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Linker Problem

Beitrag von starcow »

Hi Hannes!

Im Moment sieht die Fehlermeldung so aus, nachdem ich zurück bin, zum ursprünglichen Setup:

Code: Alles auswählen

1>F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_renderer.h(22,29): error C2079: 'beast::CLS_Renderer::camera' uses undefined class 'beast::CLS_RENDERER_Camera'
cls_renderer.h

Code: Alles auswählen

#pragma once

#include <iostream>
#include <vector>
#include "types.h"
#include "cls_renderer_camera.h"
#include "sdl/SDL.h"
#include "ellipse.h"

namespace beast {
	class CLS_Renderer {
	private:
		const int WIDTH;
		const int HEIGHT;
		SDL_Window* SdlWindow;
		SDL_Renderer* SdlRenderer;
		std::vector<STR_RENDERER_Circle> circle_VEC;
		std::vector<STR_RENDERER_Line> line_VEC;

	public:
		CLS_RENDERER_Camera camera;
		
		CLS_Renderer();
		~CLS_Renderer();
		bool Init();
		void Render();
		void CreateCircle(STR_RENDERER_Circle);
		void CreateLine(STR_RENDERER_Line);
	};
}
cls_renderer_camera.h

Code: Alles auswählen

#pragma once

#include <iostream>
#include "types.h"
#include "cls_vector2d.h"
#include "cls_character.h"

namespace beast{
	class CLS_RENDERER_Camera {
	private:
		CLS_Character* Character;
		CLS_Vector2d position;
		const CLS_Vector2d* _Position;

	public:
		const CLS_Vector2d*& Position;
		void Bind();
		void Disband();

		CLS_RENDERER_Camera();
		~CLS_RENDERER_Camera();
	};
}
Edit:
Eine Vorwärtsdeklaration von cls_renderer_camera bringt auch keine Hilfe - und den header habe ich ja eingebunden. Verstehe nicht, wieso er sich dennoch beschwert. Mehr kann ich ja nicht tun...?
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Linker Problem

Beitrag von Schrompf »

Klingt, als willst Du eigentlich namespace, wenn Du solche Namenstechniken benutzt. Ein echtes Problem kann ich hier nicht erkennen, aber ich spekuliere wie Hannes, dass Du zirkuläre Includes hast. Die (Compiler, nicht Linker!)-Fehlermeldung besagt jedenfalls: Du benutzt eine Klasse, die an der Stelle nur vorwärtsdeklariert ist. Du inkludierst dort korrekt cls_renderer_camera.h, aber ins Blaue geraten würde ich vermuten, dass cls_character.h irgendwo cls_renderer.h inkludiert.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Linker Problem

Beitrag von starcow »

Schrompf hat geschrieben: 03.01.2020, 12:07 Klingt, als willst Du eigentlich namespace, wenn Du solche Namenstechniken benutzt. Ein echtes Problem kann ich hier nicht erkennen, aber ich spekuliere wie Hannes, dass Du zirkuläre Includes hast. Die (Compiler, nicht Linker!)-Fehlermeldung besagt jedenfalls: Du benutzt eine Klasse, die an der Stelle nur vorwärtsdeklariert ist. Du inkludierst dort korrekt cls_renderer_camera.h, aber ins Blaue geraten würde ich vermuten, dass cls_character.h irgendwo cls_renderer.h inkludiert.
Hi Schrompf

Danke für die Schnelldiagnose :-)
Wie meinst du dass mit namespace? Ich dachte, es wäre sinnvoll die Klassen unter einem separaten Namensraum zu definieren, um mögliche Namenskollisionen zu verhindern.

cls_character.h inkludiert lediglich cls_renderer_camera.h. Müsste es das nicht sowieso egal sein? Jeder Header kann doch durch #pragma once sowieso nur einmal eingebunden werden.
Wie ist es denn möglich, dass er diese Definition nicht kennt. Die ist doch da - der Header ist eingebunden...
Sollte ich vielleicht mal einfach alles in ein File auslagern?

Edit:
Oder ich könnte jeweils die ganze Klasse, inklusive Body in einem separates File speichern und dieses File dann einfach per include in die main einfügen. Also quasi inline. Das müsste dann noch gehen, sofern als erstes Vorwärtsdeklarationen von den Klassen aufgeführt sind.

Code: Alles auswählen

// Vorwärtsdeklaration
class cls_character;
class cls_renderer_camera;
...

// inline inkludieren
#inklude "cls_character.cpp"
#inklude "cls_renderer_camera.cpp"

// main
int main(...){}

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Linker Problem

Beitrag von Schrompf »

Du bekommst vor der Fehlermeldung üblicherweise eine lange Kette von "In file included from blablubb.h:23", anhand der Du die Include-Schachteltiefe und -reihenfolge erkennen kannst. Schau Dir die mal an, ob Du daraus was lernen kannst.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Linker Problem

Beitrag von starcow »

Gibts in VS vielleicht noch ne detailliertere Log? Weil unter "Build" kriege ich nur eine einzelne Fehlermeldung (die genannte):

Code: Alles auswählen

1>------ Build started: Project: sdl-collision, Configuration: Debug Win32 ------
1>cls_area.cpp
1>cls_area_cell.cpp
1>cls_character.cpp
1>cls_circle.cpp
1>cls_circle_link.cpp
1>cls_engine.cpp
1>cls_line.cpp
1>cls_renderer.cpp
1>cls_renderer_camera.cpp
1>F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_renderer.h(24,29): error C2079: 'beast::CLS_Renderer::camera' uses undefined class 'beast::CLS_RENDERER_Camera'
1>main.cpp
1>Generating Code...
1>Done building project "sdl-collision.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
 
Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Linker Problem

Beitrag von Schrompf »

Rechte Maustase auf der einen Datei, die Du brauchst, "Eigenschaften" -> "C/C++" -> "Erweitert" -> "Includes anzeigen".
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Linker Problem

Beitrag von starcow »

Danke für die Hilfe Schrompf.
Ok! Also cls_renderer_camera.cpp bindet neben seitenweise sdl-dateien laut Log folgendes ein:

Code: Alles auswählen

1>Note: including file: F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_renderer_camera.h
1>Note: including file:   F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_vector2d.h
1>Note: including file:  F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_character.h
1>Note: including file:   F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_engine.h
1>Note: including file:    F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_area.h
1>Note: including file:     F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_circle.h
1>Note: including file:      F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_line.h
1>Note: including file:      F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_circle_link.h
1>Note: including file:       F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_area_cell.h
1>Note: including file:    F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_input.h
1>Note: including file:    F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_renderer.h
1>Note: including file:     F:\GAME\beast\code\sdl-collision\sdl-collision\source\ellipse.h

1>F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_renderer.h(24,29): error C2079: 'beast::CLS_Renderer::camera' uses undefined class 'beast::CLS_RENDERER_Camera'

1>Note: including file:    F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_time.h
1>Note: including file:     F:\GAME\beast\code\sdl-collision\sdl-collision\source\cls_time_clock.h
Irgendwann dazwischen dann die Fehlermeldung...
Folglich werden all meine Klassen mit eingebunden - was auch zu erwarten war, da diese untereinander diese Abhängigkeit erzeugen.
Es bleibt mir schleierhaft, wieso er die Klasse nicht erkennen will.
Kann man nicht eine Klasse in je ein File packen? Vielleicht würde es dadurch etwas klarer - auch um daran zu arbeiten...

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Linker Problem

Beitrag von Schrompf »

Schreib mal Bullshit in die Klassendefinition und guck, ob er da überhaupt vorbeikommt.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Linker Problem

Beitrag von starcow »

Ja, der kommt vorbei und produziert Compiler-Fehler. :-/ Wenn ich "CLS_RENDERER_Camera camera;" auskommentiere kompiliert er... :-/

Edit:
Wenn ich einen Zeiger daraus mache - also

Code: Alles auswählen

CLS_RENDERER_Camera* camera
dann wirds kompiliert! WTF?!
Freelancer 3D- und 2D-Grafik
mischaschaub.com
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Linker Problem

Beitrag von Schrompf »

Hm, das wiederrum sind C++-Grundlagen. Du hast dort eine nur vorwärtsdeklarierte Klasse und keine richtig definierte Klasse - das ist der Fehler, den Du beheben willst. Alles andere ist eine Folge davon: für Zeiger und Referenzen reicht Vorwärtsdeklaration, weil ein Zeiger nur eine Adresse ist und nix über das verwiesene Objekt wissen muss. Aber wenn Du eine echte Instanz der Klasse einfügen willst, muss der Compiler für die Anordnung der Member wissen, wie groß eine Instanz ist. Und das weiß er nur, wenn die echte Definition der Klasse vorliegt.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Linker Problem

Beitrag von starcow »

Ok, danke, das leuchtet ein :-)

Habe eben festgestellt, dass wenn ich im File "cls_renderer_camera.h"

Code: Alles auswählen

#include "cls_character"
auskommentiere, dann wird es ebenfalls kompiliert.

Kann es vielleicht sein, dass er trotz "#pragma once" die header Dateien mehrmals einbindet?
Wieso kann das inkludieren von cls_character einen Unterschied in jener Hinsicht machen?

Edit:

Hmmm... also irgendwie mach ich da wohl einiges falsch :-(
Eigentlich dachte ich, ich hätte ein gutes Konzept:
Im Header-File der Klasse include ich einfach alle jene Header-Files, deren Definitionen ich brauche - und im CPP-File der selben Klasse include ich dann nur noch ihren eigenen Header.
Aber dieses Konzept scheint nicht aufzugehen, auch wenn mir noch nicht klar ist warum. Ich bin bis jetzt davon ausgegangen, dass jede (cpp) Datei, die ich dem Projekt anhänge separat kompiliert wird, und dass ich dann auf der sicheren Seite sein müsste, wenn ich die Header mit #pragma once einbinde. Aber die einzige Erklärung für mein Problem scheint mir zu sein, dass er gerade wegen dieses "#pragma once" die Datei nicht mehr einbindet - obwohl er sie bräuchte. Womöglich, weil er sie für eine andere .cpp Datei schon eingebunden hat.
Gibts vielleicht ein Verwaltungskonzept, bei welchem die Klassen in einer einzelnen Datei abgelegt werden?
Und komme ich tatsächlich nicht drum herum, in den CPP Dateien selbst, neben dem "klassen-eigenen" Header, weitere mit einzubinden?
Zudem wollte ich es eigentlich vermeiden, an verschiedenen Stellen des Programms ein - und die selbe Vorwärtsdeklaration anzubringen, sondern die einheitlich im Header-File mitanzugeben. Aber auch das scheint keine Lösung zu sein.

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
NytroX
Establishment
Beiträge: 358
Registriert: 03.10.2003, 12:47

Re: Linker Problem

Beitrag von NytroX »

Keine Sorge - das Konzept versucht jeder am Anfang. Ist halt logisch und intuitiv, aber führt irgendwann zum Haare ausreißen.


Ich versuche, das Problem nochmal einfacher zu erklären:

Code: Alles auswählen

namespace Versuch1
{
    class C2
    {
        C1 c1; //geht nicht, C1 ist keine Klasse. Liegt daran, dass es erst später deklariert wird.
    };
    class C1
    {
        C2 c2;
    };
}

Code: Alles auswählen

namespace Versuch2
{
    class C1; //Vorwärtsdeklaration 
    
    class C2
    {
        C1 c1; //geht nicht, C1 ist eine unvollständige Klasse
    };
    class C1
    {
        C2 c2;
    };
}

Aber moment, was machen wir hier eigentlich für einen Quatsch?
Eine Klasse enthält die andere Klasse, welche wiederum die 1. Klasse enthält... das kann nicht gehen!

Code: Alles auswählen

namespace Versuch3
{
    class C1; //Vorwärtsdeklaration 
    
    class C2
    {
        C1* c1; //aah, jetzt gehts (aber bitte niemals machen, der raw pointer ist hier total fehl am platz, weil er die intention nicht beschreibt; std::optional oder std::unique_ptr sind viel besser)
    };
    class C1
    {
        C2 c2;
    };
}

So, jetzt zu den #includes:
Ein #include copy-pasted lediglich den Text der anderen Datei an die Stelle des #includes.
Das ist nett, bewahrt einen aber nicht vor dem gleichen Problem wie oben.


Hier mit #includes:

Code: Alles auswählen

//C1.h
#include "C1.h" //hier brauchen wir es, weil C2 teil von C1 ist
namespace X
{
    class C1
    {
        C2 c2;
    };
}


//C2.h
//kein include nötig! C1 ist nicht teil von C2. Daher nur Vorwärtsdeklaration.
namespace X
{
  class C1;
  class C2
  {
    C1* c1;
  }
}


Noch ein paar Tipps: Im Prinzip genau das Gegenteil von dem, was man denkt:
- In .h Dateien wirklich nur das Interface definieren
- Alle #includes wenn möglich im cpp machen, nur im Header #includen wenn absolut nötig
- Immer alle Abhängigkeiten #includen. Ja, du #includest vielleicht den <vector> schon in einem anderen Header, der irgendwann irgendwo über 10 andere Header eingelesen wird, aber es ist trotzdem falsch, auch wenn es kompiliert. Genau hierfür gibt es das "#pragma once".
- Die einzigen #includes im Header sollten die der Standard-Library und andere verwendete Klassen sein - dann aber auf das Beispiel von oben aufpassen: Entweder enthält eine Klasse die andere, dann kann es ja keine zyklen geben; oder es reicht eine Vorwärtsdeklaration.
- Alle privaten methoden und variablen in die cpp verfrachten, am besten noch in einen anonymen namespace

Bonus: die Compile Zeit geht rapide nach unten und alles wird viel schneller. Auch das AutoComplete/Intellisense geht besser und schneller.

Zum ersten und letzten Punkt noch ein Beispiel von dir:

Code: Alles auswählen

namespace beast
{
  class CLS_Renderer {
  	private:
  		const int WIDTH;
  		const int HEIGHT;
  };
}
Was macht das im Interface? keiner kommt von außen dran (ist ja private) und es wird auch nirgends im Header benutzt.
Also ab damit in die cpp Datei, in den anonymen namespace:

Code: Alles auswählen

//CLS_Renderer.cpp
namespace
{
  static const int WIDTH = 800;
  static const int HEIGHT = 600;
}
namespace beast 
{
  //[...]  hier kann man WIDTH und HEIGHT wie gewohnt benutzen
}

Benutzeravatar
starcow
Establishment
Beiträge: 523
Registriert: 23.04.2003, 17:42
Echter Name: Mischa Schaub
Kontaktdaten:

Re: Linker Problem

Beitrag von starcow »

Ha! Es läuft! :-D
Wirklich sehr anschaulich und gut erklärt! Vielen lieben Dank NytroX!
Du hast natürlich recht, dass konnte so unmöglich funktionieren - genau aus diesem Grund.
Jetzt wird mir auch klar, wieso man in gewissen Situationen gar nicht anders kann, als das Objekt per Zeiger einzubinden. Gerade wenn die beiden Objekte aufeinander Bezug nehmen.
Ich habs jetzt auch so gelöst - wie von dir vorgeschlagen, dass CLS_Renderer sich eine unabhängige Instanz von CLS_Renderer_Camera auf dem Heap erstellt und diese dann per Zeiger anspricht.
Was du über das "Design-Konzept" erzählt hast, öffnet mir jetzt gleich ein neues Fenster. Und ich muss einmal mehr feststellen, wie wenig ich doch eigentlich übers Programmieren weiss :->.
Ich hatte eigentlich immer nach solchen Erklärungen gesucht. Das, was du jetzt so aus dem Ärmel geschüttelt hast, war mir komplett neu - und macht beim Lesen auch gleich Sinn. Wenn ich mich so durch C und C++ Bücher durchblättere stosse ich eigentlich immer auf die selben Grundlagen... Wo kann man denn solche Dinge lernen? Hast du vielleicht einen Tipp? Resp. welche Bücher hast denn du gelesen? Oder ist das einfach Wissen durch langjährige Erfahrung?

Edit:
Der Trick mit dem anonymen namespace ist ja wirklich sehr raffiniert!

Gruss starcow
Freelancer 3D- und 2D-Grafik
mischaschaub.com
NytroX
Establishment
Beiträge: 358
Registriert: 03.10.2003, 12:47

Re: Linker Problem

Beitrag von NytroX »

StackOverflow hilft natürlich, aber das meiste ist selbst ausprobieren.
Jeder macht es etwas anders, finde einfach, was für dich am besten passt.

Was halt auch hilft, ist, wenn man mehrere Programmiersprachen kann; jede neue Sprache eröffnet neue Perspektiven.
In C/C++ hat sich lange nichts geändert, und sie versuchen immer noch verzweifelt, Module zu bauen (Modules_TS. Dann gibts das Problem endlich nicht mehr).
D hat das schon lange.

Und in D hat man auch schon einige Probleme gelöst, die den C++ Leuten erst über den Weg laufen (werden).
"constexpr if" ist so eins, da ist in C++ einfach was falsch gemacht worden; aber da die C++ Leute keine Erfahrung mit der Nutzung eines solchen Features haben, fallen ihnen die Probleme auch nicht sofort auf.
http://www.youtube.com/watch?v=tcyb1lpEHm0&t=54m45s

Also Bücher lesen ist ok, aber selbst ausprobieren und auch mal über den Tellerrand schauen bringt einen wirklich vorwärts.
Antworten