One Definition Rule (ODR)



  • Mal eine Frage an die Experten...

    Wiederspricht der folgende Code der ODR?
    http://en.wikipedia.org/wiki/One_Definition_Rule

    Also: Ist dies *legaler* C++ Code???

    Kurz:
    In *zwei* *CPP*-Dateien wird der gleiche Name für überschiedliche "typedef struct" verwendet.
    Ist dies erlaubt???

    Hier der (simple) Code (man beachte den Unterschiedlichen Inhalt von "Test"):

    Test1.cpp:

    #include <stdio.h>
    typedef struct
    {
      int a;
      bool b;
    } Test;
    static Test t;
    void Test1()
    {
      printf("%d", t.a);
    }
    

    Test2.cpp:

    #include <stdio.h>
    typedef struct
    {
      bool a;
      int b;
    } Test;
      static Test t;
    void Test2()
    {
      printf("%d", t.a);
    }
    

    main.cpp:

    #include <tchar.h>
    extern void Test1();
    extern void Test2();
    int _tmain()
    {
      Test1();
      Test2();
      return 0;
    }
    


  • Wie sieht der Inhalt von Test1.h und Test2.h aus?
    Ich nehme einfach mal an sie sind leer.

    Dann sehe ich hier keine Verletzung der ODR.

    Wobei ich zugeben muss es nicht 100% zu wissen, da ich mich erinnere von Sutter etwas gelesen zu haben wo es um unamed namespaces VS static ging und static mit irgendetwas ein Problem hatte (mal von dem offensichtlich Template-Problem abgesehen).

    Wenn du hier aber unnamed namespaces verwenden wuerdest, waere es keine ODR Verletzung.


  • Mod

    Jochen Kalmbach schrieb:

    Ist dies *legaler* C++ Code???

    Nein.
    Es ist allerdings legaler C-Code (wenn ich mal den reservierten Bezeichner _tmain ignoriere).

    Klassennamen (und typedef-Namen, die unbenannte Klassen, welche in typedef-Deklarationen definiert wurden, bezeichen ... *luftholen*) haben in C++ external linkage - gleichlautende Bezeichner mit external linkage in verschiedenen ÜEs müssen aber die gleiche Entität bezeichnen. Die definierten Klassen sind offensichtlich nicht gleich (unterschiedliche Tokenfolge). Derartige Verletzungen der ODR - also unterschiedliche Definitionen in unterschiedlichen ÜEs - haben undefiniertes Verhalten, müssen also nicht diagnostiziert werden. Ein solches Programm ist ill-formed.

    In C haben Typnamen generell no linkage - in C verlässt man sich beim Transport von Objekten in andere ÜEs auf strukturelle Äquivalenz (also die gleiche Folge der Strukturelemente).



  • Shade Of Mine schrieb:

    Wie sieht der Inhalt von Test1.h und Test2.h aus?

    Sorry... hab sie wegoptimiert 😉

    Shade Of Mine schrieb:

    Ich nehme einfach mal an sie sind leer.

    Ja.

    Shade Of Mine schrieb:

    Wenn du hier aber unnamed namespaces verwenden wuerdest, waere es keine ODR Verletzung.

    Meine Frage ist, ob es auch ohne namespace gültiger Code ist?

    PS: Lt. MS ist es dies nicht... obwohl weder Compiler- noch Linker-Warning/Error ausgegeben wird...



  • Wo wäre denn der unterschied zu nem header, der in beide ÜE eigebunden wird, und den der eigentliche compiler ja nie zu sehen bekommt?



  • So, hab den text gefunden: http://www.ddj.com/cpp/184403830
    Da steht nichts drinnen warum dein Code die ODR verletzen sollte. War nur ein allgemeiner Hinweis unnamed namespaces zu verwenden.

    Aber ich habe die Klassendefinitionen uebersehen. Camper hat recht. Die Variablendefinition verletzt die ODR zwar nicht, aber die Klassendefinition tut dies.



  • quarkquark schrieb:

    Wo wäre denn der unterschied zu nem header, der in beide ÜE eigebunden wird, und den der eigentliche compiler ja nie zu sehen bekommt?

    Ahhh die reihenfolge ist vertauscht. Gut dann nicht



  • Also, es verletzt die ODR, oder?

    Gibt es irgendeinen Compiler/Linker auf der Welt, der hier ein Fehler ausgibt?



  • Wenn er es nicht tun würde, würde mich das wundern.

    Schließlich wird zuerst Test1.cpp kompiliert, dann Test2.cpp (und noch Main.cpp...). Beide enthalten eine Klasse die den Namen "Test" hat.
    Wenn die beiden dateien zusammengelinkt werden, müsste das doch einen Linker fehler erzeugen, oder habe ich da etwas missverstanden?



  • Jochen Kalmbach schrieb:

    Also, es verletzt die ODR, oder?

    Gibt es irgendeinen Compiler/Linker auf der Welt, der hier ein Fehler ausgibt?

    g++ in Version 4.2 und 4.3 sowie comeau in Version 4.3.3 geben in maximaler Warnstufe keine Warnungen/Fehler


  • Mod

    DrPhil_Guth schrieb:

    Wenn die beiden dateien zusammengelinkt werden, müsste das doch einen Linker fehler erzeugen, oder habe ich da etwas missverstanden?

    Warum? In dem Beispiel ist nicht zu sehen, warum der Linker den Typ Test jemals benutzen müsste. Ganz analog zu mehrfach definierten Funktionen, mit dem Fall sind wir ja einigermaßen vertraut, führt das in der Regel nur zu Problemen, wenn diese Funktion tatsächlich auch benutzt wird, vorzugsweise aus einer anderen Übersetzungseinheit heraus. Benutzen muss der Linker den Typ aber nur, wenn eine andere Entität, mit der er sich sowieso auseinandersetzen muss, daran anknüpft - also ein Objekt (dass Member sein könnte, so dass der für den Linker sichtbare Name auch vom Typ abhängt) oder eine Funktion, deren Signatur von diesem Typ mit abhängt; evtl. auch ein Template. Geht man von einem simplen Compiler/Linker-Modell aus, wäre es in diesem Beispiel sehr überraschend, falls dieser ODR-Verletzung überhaupt diagnostiert werden könnte.



  • Die ODR Verletzung kann vom Linker auf jeden Fall diagnostiziert werden.

    Das Problem was ich nämlich mit dem Code habe, ist dass VC9 RTM hier "falsche" PDB-Dateien erzeugt und dort nur *einer* der beiden Typen landet...
    Der Linker hat also alle Typen und kann auch logischerweise feststellen, ob Typen doppelt (mit unterschiedlicher Definition) vorhanden sind...

    Hier ist die Aussage den MS-Supports:

    Problem/Issue:

    We have defined two structures with same name in two different CPP files. It compiles and works fine. When we see the data member information in the watch section, it shows the last compiled structure data type. This does not happen with previous version of Visual Studio.

    A: (Assessment)
    SUMMARY of TROUBLESHOOTING

    - Further to my research the issue is happening due to the PDB file is getting overwritten using the last compiled type definition information.
    - This issue does not occur in VS2008 SP1 Beta.
    - During the research we found that this not as part of the C++ standards [The C++ Standard (ISO/EC 14882:2003), section 3.2]

    RESOLUTION

    - We can keep the types under namespace or give different names for the types.


  • Mod

    Jochen Kalmbach schrieb:

    Die ODR Verletzung kann vom Linker auf jeden Fall diagnostiziert werden.

    Was ist der Linker? Ich habe mich ja bewusst nicht auf eine bestimmte Implementation bezogen - zweifellos ist es nicht prinzipiell unmöglich, derartige Fehler automatisch zu erkennen. Diese Diagnose aber in jedem Falle zu verlangen, erhöht die Komplexität einer minimalen Implementation in unerwünschter Weise - die Konsequenz ist, dass der Standard zum Verhalten bei solchen Fehlern keine Aussage trifft, dieses also undefiniert bleibt.



  • camper schrieb:

    die Konsequenz ist, dass der Standard zum Verhalten bei solchen Fehlern keine Aussage trifft, dieses also undefiniert bleibt.

    Das hab ich jetzt nicht ganz verstanden...
    Ich dachte die ODR ist Teil des Standards!?

    [The C++ Standard (ISO/EC 14882:2003), section 3.2]

    !?

    Oder doch nicht?

    Was meinst Du mit "undefiniert"? Ich dachte es *ist* gerade definiert!


  • Mod

    Jochen Kalmbach schrieb:

    camper schrieb:

    die Konsequenz ist, dass der Standard zum Verhalten bei solchen Fehlern keine Aussage trifft, dieses also undefiniert bleibt.

    Das hab ich jetzt nicht ganz verstanden...
    Ich dachte die ODR ist Teil des Standards!?

    [The C++ Standard (ISO/EC 14882:2003), section 3.2]

    !?

    Oder doch nicht?

    Was meinst Du mit "undefiniert"? Ich dachte es *ist* gerade definiert!

    Es ist definiert, ob ein Programm die ODR verletzt oder nicht. Der Standard sagt nicht, wie eine Implementation zu reagieren hat, wenn ein Programm diesen besonderen Teil der ODR verletzt.


Log in to reply