Postinkrement, priorität



  • Hallo,

    Ich als alter Pascal programmierer bin neu in der C Welt und muss mich durch verschiedene Bereiche kämpfen, wie jetzt zbsp:

    Aufgabe:

    int array[10]={1,2,3,4,5,6,7,8,9,10}
    int *a, *b;
    
    a=ia;
    *a++=7;
    

    Es geht um die Zeile *a++=7;
    Laut einer Musterlösung passiert folgendes: *a=7; und dann a++; //*a=7 bedeutet ja:ia[0]=7; und a++ bedeutet dass die Adresse um 4Bytes inkrementiert wird, also zeigt a jetzt auf ia[1]
    Dann steht in der MusterLösung noch folgendes:

    *a++ entspricht nach der Priorität der Operatoren *(a++)

    Und das ergbibt für mich kein Sinn. Da laut der Priorität wie in diesem Zitat zuerst a++ ausgeführt werden müsse, und dann *a=7, aus dem Grund da a++ in Klammern steht und Klammern ja IMMER zuerst ausgeführt werden müssten ?

    Hoffe meine Frage war verständlich,
    freue mich auf gute Antworten, danke Vielmals im Voraus!! 🙂 (voraus mit 2 r wird mit * ersetzt :p )



  • newinc schrieb:

    Hallo,

    Ich als alter Pascal programmierer bin neu in der C Welt und muss mich durch verschiedene Bereiche kämpfen, wie jetzt zbsp:

    Aufgabe:

    int array[10]={1,2,3,4,5,6,7,8,9,10}
    int *a, *b;
    
    a=ia;
    *a++=7;
    

    Es geht um die Zeile *a++=7;
    Laut einer Musterlösung passiert folgendes: *a=7; und dann a++; //*a=7 bedeutet ja:ia[0]=7; und a++ bedeutet dass die Adresse um 4Bytes inkrementiert wird, also zeigt a jetzt auf ia[1]
    Dann steht in der MusterLösung noch folgendes:

    *a++ entspricht nach der Priorität der Operatoren *(a++)

    Und das ergbibt für mich kein Sinn. Da laut der Priorität wie in diesem Zitat zuerst a++ ausgeführt werden müsse, und dann *a=7, aus dem Grund da a++ in Klammern steht und Klammern ja IMMER zuerst ausgeführt werden müssten ?

    Hoffe meine Frage war verständlich,
    freue mich auf gute Antworten, danke Vielmals im Voraus!! 🙂 (voraus mit 2 r wird mit * ersetzt :p )

    Bedenke, daß a++ zwar a erhöhet, der Wert von a++ ist aber das alte unerhöhte a.
    Damit tut *a++ auch soviel wie erst *a anzuschauen und später irgendwann den Seiteneffekt des Erhöhens von a auszuführen.
    Also wenn ich http://de.cppreference.com/w/cpp/language/operator_precedence anscheie, dann steht da echt *(a++). Ja, a++ wird zuerst ausgewertet (was aber ja den alten Wert ergibt). Mir scheint die Musterlösung richtig (wenn auch ein wenig verwirrend).



  • Die Priorität und die Reihenfolge der Ausführung sind zwei Dinge, die nichts miteinander zu tun haben. Die Priorität sagt dir (und besonders dem Compiler) lediglich, dass *a++ wie *(a++) zu interpretieren ist, d.h. dass der Wert des Ausdrucks a++ dereferenziert wird.



  • volkard schrieb:

    Ja, a++ wird zuerst ausgewertet (was aber ja den alten Wert ergibt). Mir scheint die Musterlösung richtig (wenn auch ein wenig verwirrend).

    Hab jetzt noch folgendes entdeckt:

    Postfix ( a++ ) Bei der Postfix-Notation wird die Variable inkrementiert, nachdem sie verwendet wurde

    Das heisst laut Priorität, wird ja zuerst a++ ausgeführt. Da dies doch ein Postifix ist, wird es erst zum Schluss "wirklich" ausgeührt, und desswegen zuerst *a und dann a++, da a ja dann verwendet wurde.
    http://de.wikibooks.org/wiki/C-Programmierung:_Ausdr%C3%BCcke_und_Operatoren

    Versteh ich das richtig ?



  • Du kannst dir das Postinkrement als eine Funktion etwa wie (jetzt mit Integern statt Zeigern)

    int postincrement(int *x) {
      int r = *x;
      *x += 1;
      return r;
    }
    

    vorstellen. Dann ist

    int x = 0;
    
    printf("%d\n", postincrement(&x)); // gibt 0 aus
    
    // Hier ist x == 1
    

    genauso wie

    int x = 0;
    
    printf("%d\n", x++); // gibt 0 aus
    
    // Hier ist x == 1
    

    Jetzt ist mit diesen Nebeneffekten etwas Vorsicht geboten; die genauen Regeln, wann das Inkrement eingetreten sein darf und wann es eingetreten sein muss, sind recht lose gehalten, um Compilern Freiraum bei der Optimierung zu geben. Faustregel: Es ist keine gute Idee, eine Variable in einem Ausdruck zu inkrementieren/dekrementieren, in dem sie zweimal benutzt wird, denn:

    int x = 0;
    
    int y = x + x++;
    // Wert von y ist nicht spezifiziert.
    
    some_function(x++, x); // Werte der Parameter, die an some_function übergeben werden, sind nicht spezifiziert.
    

    "nicht spezifiziert" bedeutet hier, dass der C-Standard keine Aussage darüber macht, welche Werte die Variable annimmt, so dass das z.B. abhängig vom Compiler oder Compilerflags unterschiedlich sein kann. Das liegt daran, dass der C-Standard nicht vorgibt, in welcher Reihenfolge die Summanden bzw. Funktionsparameter ausgewertet werden. Etwa ist bei

    int f(void) { putchar('f'); return 0; }
    int g(void) { putchar('g'); return 1; }
    
    int h(int x, int y) { puts('h'); return x + y; }
    
    ...
    
    int y = f() + g();
    h(f(), g());
    

    zwar definiert, dass y den Wert 1 hat, aber nicht ob "fgfgh", "gfgfh", "fggfh" oder "gffgh" ausgegeben wurde.

    Die genaue Regelung ist beispielsweise hier beschrieben.



  • Um mal die andere Möglichkeit der Klammerung zu beleuchten : (*a)++

    Hier wird der Wert, auf den a zeigt verändert.
    Was gerade mit einer Zuweisung, wie bei deinem Beispiel, undefiniertes Verhalten ergibt:

    (*a)++=7;  // undefiniertes Verhalten (UB)
    

  • Mod

    DirkB schrieb:

    Um mal die andere Möglichkeit der Klammerung zu beleuchten : (*a)++

    Hier wird der Wert, auf den a zeigt verändert.
    Was gerade mit einer Zuweisung, wie bei deinem Beispiel, undefiniertes Verhalten ergibt:

    (*a)++=7;  // undefiniertes Verhalten (UB)
    

    Das Ergebnis des Postinkrements ist ein rvalue, das sollte also gar nicht erst kompilieren.



  • Hi,

    die Pioritäten bzw. Klammern besagen nur, in welcher Reihenfolge die Teilausdrücke evaluiert werden. Wann der Increment bzw. der Dekrement erfolgt, hat damit nichts zu tun.

    Der Wert von a++ ist IMMER a Der Wert von ++a ist IMMER a+1 auch wenn da noch Klammern drumherum stehen.


Log in to reply