namespace Problem
-
Meines Wissens besagt die ODR nicht, dass es keine Mehrfachdefinitionen derselben Funktion oder Klasse geben darf. Sie besagt lediglich, dass alle Definitionen einer Funktion/Klasse identisch sein muessen.
-
3.2 - One Definition Rule
1 No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template.
was du meinst gehört auch dazu:
5 There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template clause 14), non-static function template (14.5.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template special ization for which some template parameters are not specified (14.7, 14.5.4) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements.
[...]
- each definition of D shall consist of the same sequence of tokens
[...]
-
Const hat nicht nur informativen Charakter - const erlaubt dem Compiler, gewisse Sachen ggü. dem Programmierer durchzusetzen. Das hat nichts mit Optimierungen zu tun, sondern mit der Einhaltung von Verträgen.
ist doch bei inline fast genau so ...
virtual inline, oder inline virtual mosert mein compiler zumindest an ^^
genau so wie er es ned mag, wenn ich von ner inline funktion nen pointer ziehen will.
Ok, const vielleicht bissi doof gewaehlt, weil ich mit const die restriktion and die benutzer meiner Bib weitergeben kann ...
Obwohl, wenn nen anderer Programmierer ne funktion als inline sieht, dann sollt es ihn auch irgendwie davon abhalten, nen funktionspointer zu ziehen.Ciao ...
-
Ok, hab noch mal beim Stroustroup nachgeschaut ... der MS compiler verhaelt sich da ned 100% Standard konform.
Stroustrup meint, das man von einer funktion und deren Variablen immer auch die Adressen abfragen koennen muss,
Zitat: die Semantik einer Funktion aendert sich durch das inline nicht.Damit ist das inline wirklich ueberfluessig .... weil danach nen inline virtual keinen error liefern duerfte ... sondern das inline simpel einfach nur ausgehebelt wird.
Meines Wissens besagt die ODR nicht, dass es keine Mehrfachdefinitionen derselben Funktion oder Klasse geben darf. Sie besagt lediglich, dass alle Definitionen einer Funktion/Klasse identisch sein muessen.
Nein, die ODR sagt das nur eine Definition vorhanden sein darf !
Das inline weicht die funktion genau dahingehend auf, das es zwar mehrere definitionen geben darf, die aber die Semantik ueberall gleich sein muss.
Also inline entbindet eine funktion von der ODR ...Ciao ...
-
RHBaum schrieb:
Const hat nicht nur informativen Charakter - const erlaubt dem Compiler, gewisse Sachen ggü. dem Programmierer durchzusetzen. Das hat nichts mit Optimierungen zu tun, sondern mit der Einhaltung von Verträgen.
ist doch bei inline fast genau so ...
virtual inline, oder inline virtual mosert mein compiler zumindest an ^^
genau so wie er es ned mag, wenn ich von ner inline funktion nen pointer ziehen will.dann solltest du dir einen compiler besorgen, der das alles kann, das sollte nämlich kein problem sein.
class Foo { public: virtual ~Foo () {} //no problem }; inline void foo () {} int main () { void (*ptr) () = foo; //no problem }
-
Hab weiter Probleme, also ich hab das "extern" Objekt im Header deklariert, weil in der .cpp wars ja falsch, weil man da definiert!
Wenn ich jetzt compiliere, dann kommt als erstes ein Problem mit dem "inline":
warning: inline function: short rd::Random::rnd(...) const, used but never defined
Mh blöd. Also hab ich das inline weggemacht, und dann kam nur noch folgendes:.objs\main.o:main.cpp:(.text+0x13d): undefined reference to `rd::randomize'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)Auch blöd, hier der Code:
main.cpp
#include <iostream> #include "random.hpp" using namespace std; using namespace rd; int main() { cout << randomize.rnd(1,5) << "\n"; cout << "Hello world!" << endl; return 0; }random.hpp
namespace rd { class Random { public: Random(); short rnd(short interval_start, short interval_end) const; }; extern Random randomize; }random.cpp
#include <cstdlib> #include <ctime> #include "random.hpp" namespace rd { Random::Random() { srand(time(0)); rand(); } short Random::rnd(short interval_start, short interval_end) const { return (interval_start + rand() % (interval_end - interval_start + 1)); } }Was läuft da schief?
Wäre eigentlich ein "inline" bei der Methode "rnd" sinnvoll? Schon oder, is doch eine klitze klein winzige Methode. Hab in meinem Buch auch gelernt, Funktionen zwischen 1-2 Zeilen inline deklarieren.
Warum 1. "inline" nur im Header funktioniert, und
2. warum gibts dann überhaupt inline außerhalb des Headers, warum ist das nicht verboten? Und eigentlich ist es doch egal ob ich meine Methode in der Klasse definiere (ich weiß, da gibts eine Regel, die besagt, das alle Methoden die man in der Klasse definiert auotmatisch "inline" sind), oder in der .cpp wenn ich das doch übersichtlicher finde.
Ich glaub am besten nutz ich "inline" vorerst lieber gar nich mehr, bringt nur ärger mit sich
Und ich kan mir nicht vorstellen das mein Code dadurch so unglaublich schneller werden soll, wenn ich dazu dan nicht mal sagen kann obs am "inline" liegt, weil man ja nie sieht ob das "inline" vom Compiler beachtet wird oder nicht.MfG
Stromberg
-
ich hab dir eigentlich schon gesagt, lies dir etwas über übersetzungseinheiten durch und fang mit der ODR an

deklaration - sooft und wo du willst
definition - einmal im gesamten programm.Stromberg schrieb:
Hab weiter Probleme, also ich hab das "extern" Objekt im Header deklariert, weil in der .cpp wars ja falsch, weil man da definiert!
Wenn ich jetzt compiliere, dann kommt als erstes ein Problem mit dem "inline":
warning: inline function: short rd::Random::rnd(...) const, used but never definedwie schon gesagt, inline funktionen müssen in jeder übersetzungseinheit, in der sie verwendet werden, definiert sein.
.objs\main.o:main.cpp:(.text+0x13d): undefined reference to `rd::randomize'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 0 seconds)das bedeutet, dass rd::randomize nicht definiert ist. du deklarierst es zwar, aber es wird nirgendwo tatsächlich instanziiert.
Was läuft da schief?
Wäre eigentlich ein "inline" bei der Methode "rnd" sinnvoll?
wahrscheinlich ist es egal. wenn du den code oft austauschst eher nicht. ansonsten definiere die methode am besten direkt in der klassendefinition.
Schon oder, is doch eine klitze klein winzige Methode. Hab in meinem Buch auch gelernt, Funktionen zwischen 1-2 Zeilen inline deklarieren.
Warum 1. "inline" nur im Header funktioniert, und
2. warum gibts dann überhaupt inline außerhalb des Headers, warum ist das nicht verboten? Und eigentlich ist es doch egal ob ich meine Methode in der Klasse definiere (ich weiß, da gibts eine Regel, die besagt, das alle Methoden die man in der Klasse definiert auotmatisch "inline" sind), oder in der .cpp wenn ich das doch übersichtlicher finde.ich sagte: lies dir was zu übersetzungseinheiten durch. anscheinend muss ich wohl selbst ausholen

der compiler bekommt header-dateien niemals zu gesicht. ein compiler übersetzt immer nur einzelne übersetzungseinheiten.
was ist eine übersetzungseinheit?
wenn du dem compiler sagst, er soll eine datei, nennen wir sie foo.cc kompilieren, dann lässt er zunächst einmal den präprozesser drüberlaufen. der präprozessor ist eine textersetzungsmaschine. jedes #include <datei>, dass er in foo.cc findet, wird durch den inhalt der jeweiligen datei ersetzt. der kompiler bekommt am ende also nur noch eine foo.cc datei zu gesicht, in der alle includes durch die entsprechenden inhalte ersetzt sind. diese temporäre datei übersetzt der compiler nun - und das ist eben eine übersetzungseinheit.
der compiler macht nun idR eine weitere temporäre datei daraus, oft objektdatei genannt; das ist noch kein fertiges programm. die entitäten, die in dieser objektdatei nämlich nicht definiert sind, müssen irgendwo anders definiert sein (in einer anderen objektdatei). wenn du also in einer übersetzungseinheit eine variable als "extern" deklarierst, bedeutet das, dass der compiler sie in *dieser* übersetzungseinheit nicht initialisieren muss, weil sie in einer *anderen* übersetzungseinheit initialisiert (=definiert) wird.
man braucht nun also auch ein programm, das alle objektdateien durchsieht und die definitionen mit den deklarationen verbindet. das ist ein binder oder auch: linker.und der linker ist es auch, der die fehlermeldung "undefined reference to ..." ausgibt. er sucht nach einer definition, weil in einer objektdatei eine externe variable deklariert wird, findet aber in keiner übersetzungseinheit die tatsächliche variable. klar, dass das einen fehler erzeugt.
umgekehrt: wird in mehreren übersetzungseinheiten dieselbe variable definiert (und nicht manuell vor dem linker "versteckt"), dann findet der linker für eine deklaration mehrere mögliche definitionen (in verschiedenen objektdateien) und er gibt eine fehlermeldung à la "mulitple definitions found" aus.
und mit inline kann man genau dieses problem umgehen - dafür ist inline da.
-
Mh, so ganz versteh ich da was noch nicht. Schätzungsweise ich habe:
main.cpp#include "foo.hpp" int main() { return 0; }foo.hpp
#include "test.hpp" class B { }foo.cpp
#include "foo.hpp" B::B() { ..... }test.hpp
class test { }test.cpp
#include "test.hpp" test::test() { }1. Mit welcher Headerdatei wird begonnen?
2. Eigentlich sollte er doch mit "main.cpp" anfangen, weil dadurch werden ja alle Präprozessoredirektiven durchlaufen?
In "main.cpp" müsste doch dann eigentlich stehen:class B { } B::B() { ..... } class test { } test::test() { ..... } int main() { return 0; }Oder? Also gibt es doch nur eine Übersetzungseinheit (weil ich les immer was von Übersetzungseinheiten, aber warum)? Was bringt es erst "foo.hpp" zu durchlaufen, dann bekommt man ja nur die Headerdateien die bei "foo.hpp" drinstehen (hier "test.hpp"). Mit der "main.cpp" werden ja alle auf einen Schlag vom Präprozessor aufgelöst, main ist sozusagen die Grundwurzel und von ihr gehen ganz viele Wurzeln aus weg, und von diesen wieder welche.....
Warum also "Übersetzungseinheiten"?MfG
StrombergPS: Was sind "entitäten"?
-
du lässt deine programme anscheinend immer über deine IDE kompilieren
wenn du den compiler mal direkt in der konsole öffnen würdest, wäre dir einiges klarer.du rufst den compiler idR für jede *.cpp-datei auf. aus jeder *.cpp-datei wird also eine übersetzungseinheit.
wenn der präprozessor über die main.cpp drübergelaufen ist, sieht der code so aus:
class test { }; class B { }; int main () { };der code aus den anderen *.cpp dateien wird ja nirgends inkludiert (mit include), deshalb ist er in der übersetzungseinheit "main" auch nicht enthalten.
analog sieht bar.cpp dann nach dem präprozessor so aus:
class test { }; class B { }; B::B() { ..... }und test.cpp nach dem präprozessor so:
class test { }; test::test() { ..... }das macht drei übersetzungseinheiten.
und jetzt überprüfe mal, ob die one-definition rule stimmt: ist test::test() nur in einer übersetzungseinheit definiert? ja, in test.cpp. B::B ist nur in bar.cpp definiert und main nur in main.cpp."einen moment", wirst du sagen, was ist mit den definitionen der klassen?
die klassen test und B sind ja in allen drei übersetzungseinheiten definiert."ja", werde ich antworten, denn die ODR gilt für klassendefinitionen nicht. (3.2/5)
-
Stromberg schrieb:
PS: Was sind "entitäten"?
alles, was da ist. objekte, funktionen, klassen, templates, ...
-
Selbst wenn er die IDE benutzt: er brauch blos in das Output-Fenster der IDE schauen, da steht was alles passiert. Ist ja nicht so, das er ne Taste drückt und es wird ihm alles vorenthalten. Ja, auch der MSVC gibt alles aus. Man kann sogar das Verbose-Parameter mitgeben, dann wird man mit Infos überschüttet. Weiterhin kann man ja auch mal in das Projektverzeichnis schauen, da liegen auch die ganzen Objekt-Dateien. Und wenn man die im Explorer neben den dazugehörigen CPP-Dateien sieht... also, da muß einem ein Licht aufgehen!
-
Artchi schrieb:
Selbst wenn er die IDE benutzt: er brauch blos in das Output-Fenster der IDE schauen, da steht was alles passiert. Ist ja nicht so, das er ne Taste drückt und es wird ihm alles vorenthalten. Ja, auch der MSVC gibt alles aus. Man kann sogar das Verbose-Parameter mitgeben, dann wird man mit Infos überschüttet. Weiterhin kann man ja auch mal in das Projektverzeichnis schauen, da liegen auch die ganzen Objekt-Dateien. Und wenn man die im Explorer neben den dazugehörigen CPP-Dateien sieht... also, da muß einem ein Licht aufgehen!
ich formuliere es wohl lieber als "das war anscheinend die IDE" als "du bist wohl zu *** dafür"

-
Also den Kompiliervorgang hab ich jetzt mal TOP verstanden. Für die gute Erklärung schon mal ein Dankeschön.
Nur was eine Objektdatei genau ist, das ist mir noch nicht so ganz klar, bzw. irgendwie zu abstrakt. Also eine Übersetzungseinheit ist halt einfach eine große .cpp Datei, in der noch ganz viele Deklarationen drin stehen. Kann man eine Übersetzungseinheit noch in einem Editor anschauen? Oder is die schon irgendwie codiert, kp..?
Zumindestens, wird aus der Übersetzungseinheit ja dann eine Objektdatei erstellt. Ist diese noch für den Menschen lesbar, oder kann die nur noch der Linker lesen? Ist das schon irgendwie Binärcode...?
Nach dem alle Objektdateien gelinkt wurden, also die Deklarationen mit den Definitionen verbunden wurden, was kommt dann da raus? Kommt da schon die .exe raus? Die nur aus binärcode, bzw. Maschienencode besteht raus? Oder vll. eine Megaobjektdatei?
Geht es jetzt nochmal zurück vom Linker zum Compiler, der daraus letztendlich die .exe macht?Würde mich mal so interessieren. Ich hoffe das man hier jetzt nicht zu sehr ins Detail vom Computeraufbau etc. gehen muss, weil sonst fehlt mir wohl leider das nötige Vorwissen (bin kein Informatikstudent o.ä. nur n kleiner Hobby Porgrammierer). Wenn ja is auch nicht so schlimm.
Und noch was, du sagtest vorhin:
und mit inline kann man genau dieses problem umgehen - dafür ist inline da
Welche Probleme? Meinst du jetzt "multiple definitions found", "undefined reference to"....? Wie soll ich das mit "inline" lösen?
MfG
Stromberg
-
Stromberg schrieb:
Nur was eine Objektdatei genau ist, das ist mir noch nicht so ganz klar, bzw. irgendwie zu abstrakt. Also eine Übersetzungseinheit ist halt einfach eine große .cpp Datei, in der noch ganz viele Deklarationen drin stehen. Kann man eine Übersetzungseinheit noch in einem Editor anschauen? Oder is die schon irgendwie codiert, kp..?
Zumindestens, wird aus der Übersetzungseinheit ja dann eine Objektdatei erstellt. Ist diese noch für den Menschen lesbar, oder kann die nur noch der Linker lesen? Ist das schon irgendwie Binärcode...?fast schon assembler. solltest du also nicht versuchen, zu lesen.
Nach dem alle Objektdateien gelinkt wurden, also die Deklarationen mit den Definitionen verbunden wurden, was kommt dann da raus? Kommt da schon die .exe raus? Die nur aus binärcode, bzw. Maschienencode besteht raus? Oder vll. eine Megaobjektdatei?
nö, dann ist das programm fertig.
Geht es jetzt nochmal zurück vom Linker zum Compiler, der daraus letztendlich die .exe macht?
nope

Würde mich mal so interessieren. Ich hoffe das man hier jetzt nicht zu sehr ins Detail vom Computeraufbau etc. gehen muss, weil sonst fehlt mir wohl leider das nötige Vorwissen (bin kein Informatikstudent o.ä. nur n kleiner Hobby Porgrammierer). Wenn ja is auch nicht so schlimm.Welche Probleme? Meinst du jetzt "multiple definitions found"?
genau das. inline erlaubt dir, mehrere definitionen in unterschiedlichen übersetzungseinheiten zu haben, und trotzdem wird der linker das auf nur eine einzige instanz der jeweiligen entität reduzieren (deshalb kann man auch zeiger auf inline-funktionen haben - also obwohl inline-funktionen in mehreren übersetzungseinheiten definiert sind, gibt es -für den linker- nur eine einzige definition.
damit hast du den gröbsten teil schonmal verstanden

-
fast schon assembler. solltest du also nicht versuchen, zu lesen.
assembler ???
ok, wenn du die binaere form eines assembly damit meinst, dann schon.
Also es eigentlich das was man als binaercode versteht, nur noch ned ganz fertig halt.@Stromberg
die objectdateien sind der binaercode von deinen Uebersetzungseinheiten. Also der output des compilierens.
Deshalb muss auch jede Ueberstzungseinheit fuer sich compilierbar sein.
Da nun nen project meist aus mehreren Uebersetzungseinheiten besteht, und nuch paar grundlegendere dinge fehlen, sind die dinger nur zwischenstufen, also anfangen kannst du mit denen nix.
Aber dafuer der Linker.
In einer Ubersetzungseinheit kannst du ja mittels den headers auf code verweisen, der in anderen uebersetzungseinheiten dann generiert wird.
Dafuer werden in der benutzenden(drauf verweisenden) Uebersetzungseinheit verweise, sogenannte Symbole generiert. Also alle externen(in ner h datei) entitäten deiner uebersetungseinheit erzeigen symbole, und die entiteaten die du verwendest aus anderen Uebersetzungseinheiten, fuer die werden mit diesen symbolen verweisse generiert.Der Linker macht letzendlich dann nur noch folgendes. Er stzt alle obj dateien zusammen, packt alle binaeren libraris dazu (.lib oder .a ) er packt das in die richtige Form (binaere definition des execution formates, exe (windows), elf, a.out) und ersetzt die Symbole mit den richtigen adressen des codes, er loest also quasi die symbole auf.
Unresolved symbol, heisst also nix anderers, als das du irgendwo irgendwas deklariert hasst, was von anderen Uebersetzungseinheiten verwendet(referenziert) wird, aber beim linken die definition dazu ned vorhanden ist.
Meist fehlende Lib, fehlende c/cpp datei (nicht im projekt) oder einfach vergessen zu implementierenvereinfacht ausgedrueckt, deine c/cpp dateien generieren den binaercode ueber nen obj file, welches mit Symbolen versetzt ist. die symbole werden quasi durch die header generiert, und der linker baut die obj's zusammen und verlinkt die ganzen symbole mit den richtigen adressen dann.
Eigentlich ist das schon grundlage. Aber die meisten Stellen wo drauf eingegangen wird sind sehr complex. kenn z.b. kein gutes c++ anfaengerbuch, wo nen guter einstieg in c++ vermittelt wird, mit modernen compilern ^^ und der STL etc ... und dann irgendwo was zum praeprozessor, compiler und linker erklaert wird.
Vielleicht kennt ja wer anderes was, was man da empfehlen kann ...
Und extra buecher zum praeproz, compiler und linker kaufen, ich weiss ned ...Ciao ...
-
In etwa kannst du dir das so vorstellen:
Die .exe ist das Buch.
Die .h sind die Inhaltsverzeichnisse der Kapitel
Die .cpp sind die KapitelDie Kapitel werden fertiggestellt -> Objektdateien und enthalten nun Verweise anhand der .h der anderen Kapitel. Wenn du das ganze nun zu einem Buch formst, werden die Kapitel ja aneinander gestellt. Dadurch verschiebt sich die Seitennummer (Speicheradresse) der Stellen auf die man sich bezieht (Funktionen etc.) und der Linker sorgt dabei dafür das diese wieder stimmen.
