definierte und undefinierte Codekonstrukte



  • Online schrieb:

    register
    

    das ist auch vom Compiler abhängig...fals ich hier jetzt auf dem richtigen Pfad bin 🙄

    inwiefern ist es vom compiler abhängig?



  • operator void schrieb:

    Und das Beispiel mit dem Postfix-Inkrement sollte wohl sein:

    int i = 1337;
    i = i++;
    

    Da ist die Ausführungsreihenfolge nämlich unspezifiziert.

    Sicher? Ich dachte, es sei spezifiziert, dass zuerst der alte Wert von i zurückgegeben wird und dann i um 1 erhöht wird.



  • Shade Of Mine schrieb:

    Online schrieb:

    register
    

    das ist auch vom Compiler abhängig...fals ich hier jetzt auf dem richtigen Pfad bin 🙄

    inwiefern ist es vom compiler abhängig?

    Ich glaube, der Compiler muss dieses Schlüsselwort garnicht beachten und kann selbst entscheiden, was er registered macht und was net.



  • a=b*c; ist auch implementierungsabhängig 🤡



  • dEUs schrieb:

    Ich glaube, der Compiler muss dieses Schlüsselwort garnicht beachten und kann selbst entscheiden, was er registered macht und was net.

    ja schon. aber was hat das mit implementations spezifischem verhalten zu tun.

    register ändert ja nicht das verhalten des codes.
    wie leuchtturm schon gesagt hat, dann wäre auch a=b*c; implementations abhängig. denn was macht der compiler damit?
    ein mul? viele add? oder ein geiler trick?



  • operator void schrieb:

    undefined und unspecified sind Sachen, die sich nicht der Aufgabensteller ausgedacht hat, sondern die in der Sprachspezifikation so beschrieben sind. "RAND_MAX" und "vector<T>::iterator" sind unspezifiziert (innerhalb einer Implementierung konsistent und logisch passend), "int* i; *i = 5;" ist undefiniert (hier kann jedes Mal alles passieren).
    Und das Beispiel mit dem Postfix-Inkrement sollte wohl sein:

    int i = 1337;
    i = i++;
    

    Da ist die Ausführungsreihenfolge nämlich unspezifiziert.

    Habe ich jetzt zuviel verraten? 😉

    Das Beispiel ist nicht unspezifiziert sondern undefiniert, denn:

    Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored

    Hier gibt es nur einen Sequence-Point, namlich am Ende der gesamten Anweisung (quasi das Semikolon). Bis dahin wir der Wert von i aber zweimal geändert und zweimal gelesen -> undefiniert.

    Unspezifiziet ist sowas:
    *p++ = *q++
    Hier ist nicht festgelegt, in welcher Reihenfolge die Seiteneffekte auftreten.
    Möglich ist z.B.
    *p = *q;
    ++p;
    ++q;

    oder
    *p = *q;
    ++q;
    ++p;

    Ein anderes Beispiel für unspezifiziert ist (aus Exceptional C++):

    int f(int& x, int y = 1) {return x += y;}
    int g(int& x) {return x/=2;}
    int main()
    {
        int i = 42;
        cout << "f(" << i << ") = " << f(i) << ", "
             << "g(" << i << ") = " << g(i) << endl;
    }
    

    Hier ist das Ergebnis abhängig von der Reiehnfolge der Parameterauswertung, welche im Standard nicht festgelegt ist.
    Ist gibt übrigens noch einen unterschied zwischen "unspecified" und "implementation-defined". "Implementation-defined behavior" muss von der Implementation dokumentiert werden. "unspecified behavior" hingegen nicht. Angewandt auf das obere Beispiel bedeutet dies, dass in der Compilerdoku nicht stehen muss, in welcher Reihenfolge der Compiler Funktionsparameter auswertet.
    }



  • cd9000 schrieb:

    "Undefiniert" und "implementationsabhängig" halte ich aber für sehr schwammig.
    Viele undefinierte Konstrukte funktionieren bei einer bestimmten Implementierung; sind sie deswegen implementierungsabhängig?

    Im Kontext von Standard-C++ sind die Begriffe keineswegs schwammig. Sie werden im Standard eindeutig definiert (1.3.5, 1.3.12 sowie 1.3.13)



  • Hallo,
    Toll - so viele Antworten!!!!!
    Aus dem Grunde auch schon mal, weil das eigentlich eine
    Anfängeraufgabe ausm Stroustrup is, die aber anscheinend
    doch auch zu Diskussionen führt unter Fortgeschrittenen.

    Ich hab nun weiter hinten in dem Buch unter C2 noch
    folgendes dazu gefunden und wollte es mal der
    Vollständigkeit halber noch anführen:

    unsigned char c1 = 64;    // wohldefiniert, ein char hat mind 8 Bit
    unsigned char c2 = 1256;    // implementierungsspezifisch
    
    // ... und ...
    
    const int size = 4*1024;
    char page[size];
    
    void f()
    {
        page[size+size] = 7;    // undefiniert
    }
    

    ...sind allerdings eben nur 2 Bsps und nicht 5, aber nun is mir klarer
    in welche Richtung das gehen soll.

    Danke Euch nochmal! 🙂



  • int i = 2;
      cout << i++ << (i++) * (i++);
    

    Ist ebenfalls undefiniert.



  • Hi,

    bei

    struct undef {
    int a;
    char b;
    long c;
    }
    

    ist auch undefiniert, in welcher Reihenfolge die Objecte im Speicher abgelegt werden.
    (daher kann man um alles auf 0 zu setzen nicht die Funktion mamset() benutzen, der man als Startadresse die Adresse von undef.a übergibt, und als Anzahl der zu überschreibenden Bytes sizeof(int) + sizeof(char) + sizeof(int).



  • c++eus schrieb:

    Hi,

    bei

    struct undef {
    int a;
    char b;
    long c;
    }
    

    ist auch undefiniert, in welcher Reihenfolge die Objecte im Speicher abgelegt werden.
    (daher kann man um alles auf 0 zu setzen nicht die Funktion mamset() benutzen, der man als Startadresse die Adresse von undef.a übergibt, und als Anzahl der zu überschreibenden Bytes sizeof(int) + sizeof(char) + sizeof(int).

    das mit den padding bytes stimmt.
    aber es ist schon definiert, dass a vor b vor c kommt. sonst wäre es ja ein blödsinn.



  • Shade Of Mine schrieb:

    c++eus schrieb:

    Hi,

    bei

    struct undef {
    int a;
    char b;
    long c;
    }
    

    ist auch undefiniert, in welcher Reihenfolge die Objecte im Speicher abgelegt werden.
    (daher kann man um alles auf 0 zu setzen nicht die Funktion mamset() benutzen, der man als Startadresse die Adresse von undef.a übergibt, und als Anzahl der zu überschreibenden Bytes sizeof(int) + sizeof(char) + sizeof(int).

    das mit den padding bytes stimmt.
    aber es ist schon definiert, dass a vor b vor c kommt. sonst wäre es ja ein blödsinn.

    wieso?
    es bleibt doch dem Compiler überlassen, inwiefern er das optimiwert.



  • c++eus schrieb:

    wieso?
    es bleibt doch dem Compiler überlassen, inwiefern er das optimiwert.

    klär mich mal auf

    was darf er optimieren?
    padding bytes? ja
    reihenfolge der variablen? nein

    solltest du anderer meinung sein, bitte die stelle im standard angeben, wo das steht. danke.



  • Hi,

    stimmt, der Compiler lässt die Variablen wo sie sind. Er füllt sie lediglich mit Füllbyte auf, um die Variablen an Zweierpotenzen beginnen zu lassen.



  • @c++eus
    Innerhalb eines Access-Levels ist die Reihenfolge der Anordnung von Membern genau definiert. In diesem Fall muss a an einer niedrigeren Adresse als b liegen, welches wiederum vor c liegen muss.



  • wendy schrieb:

    unsigned char c1 = 64;    // wohldefiniert, ein char hat mind 8 Bit
    unsigned char c2 = 1256;    // implementierungsspezifisch
    

    Der Code ist in Ordnung, aber dein Kommentar IMHO nicht. Kann char nicht auch 7 Bits haben? (rein theoretisch, ist heute natürlich Blödsinn.)



  • Ähm ?!
    Soweit ich bis jetzt gelesen (und begriffen) habe,
    ist bei den versch. Typen nur immer die Mindestgrössen
    festgelegt. Die effektive obere Grenze ist dann
    compiler-spezifisch (== implementierungsabhängig ?!).

    Also, ein char ist mind. 8 Bit gross/lang.

    Ich versteh das dann so: 8 gesetzte Bit sind ja nur 255
    und 64 < 255 < 1256, da ja char hier als Zahl betrachtet
    wird.

    ...oder?

    PS.: das war nicht mein Kommentar sondern B. Stroustrup's



  • wendy schrieb:

    Also, ein char ist mind. 8 Bit gross/lang.

    Ich versteh das dann so: 8 gesetzte Bit sind ja nur 255
    und 64 < 255 < 1256, da ja char hier als Zahl betrachtet
    wird.

    Richtig.



  • Muss ein char nach dem Standard also mindestens 8 Bit haben?
    Funktioniert das nicht auch mit 7 Bit, wenn man eine Maschine hat, bei der die Bytes 7 Bit groß sind?



  • Muss ein char nach dem Standard also mindestens 8 Bit haben?

    Yup.

    Funktioniert das nicht auch mit 7 Bit, wenn man eine Maschine hat, bei der die Bytes 7 Bit groß sind?

    Wenn ich mich recht entsinne muss eine solche Maschine in diesem Fall die 8 (oder mehr) Bits in Software simulieren.


Anmelden zum Antworten