- Labornetzteil AliExpress         
Seite 2 von 2 ErsteErste 12
Ergebnis 11 bis 18 von 18

Thema: Seltsamer Unterschied zwischen a=a+1 und a++

  1. #11
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Anzeige

    LiFePo4 Akku selber bauen - Video
    Mir ist nicht ganz klar, worum es dir hier überhaupt geht. Der Überlauf von signed Integers ist dem C-Standard nach undefiniert. Selbst wenn die Ausgabe so aussehen würde
    Code:
    ...
    126
    127
    666
    -999
    ...
    wäre das vollkommen in Ordnung.
    Nur der Überlauf von unsigned Integers ist definiert.
    MfG
    Stefan

  2. #12
    Erfahrener Benutzer Begeisterter Techniker Avatar von M1.R
    Registriert seit
    02.06.2007
    Ort
    Freiburg
    Beiträge
    213
    Zitat Zitat von sternst
    Der Überlauf von signed Integers ist dem C-Standard nach undefiniert. ...Nur der Überlauf von unsigned Integers ist definiert.
    Das habe ich nicht gewusst!
    Vielen Dank!

    M.

  3. #13
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Auch wenn der Überlauf nicht definiert ist, sollte die Variabel a dennoch nicht auf 16 Bit erweitert werden.

    Wenn man sich daran stört, sollte es vermutlich reichen die Variabel a als volatile zu deklarieren. Dann kann der Compiler nicht mehr so viel Optimieren, und im RAM wird wohl kaum ein 2 tes Byte reserviert.

    Das ist zwar nicht der eigentliche Zweck, aber Volative hilft machmal um den Optimierer zu bremsen.

  4. #14
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von Besserwessi
    Auch wenn der Überlauf nicht definiert ist, sollte die Variabel a dennoch nicht auf 16 Bit erweitert werden.
    ... und im RAM wird wohl kaum ein 2 tes Byte reserviert.
    Nicht die Variable an sich wird auf 16 Bit erweitert (und daher auch kein 2tes Byte im Speicher reserviert), sondern nur die Schleifen interne Registerkopie der Variable. Und das ist völlig legitim. Der Standard schreibt sogar vor, dass die eigentliche Operation (a++) mindestens in int (also 16 Bit) gemacht werden muss. Und da die dann mit dem Wert aufgerufene Funktion als Parameter ebenfalls ein int erwartet, entscheidet sich der Compiler halt, die lokale Registerkopie gleich ganz als 16-Bit-Wert zu führen. Und weil er sich bei einem signed Wert keine Gedanken um einen Überlauf zu machen braucht, spart er sich halt das Ausnullen des High-Bytes zwischen den beiden Operationen.

    Ein volatile wird die Situation tatsächlich verändern, denn dann wird ja die lokale Kopie (16-Bit) zwischendurch in die eigentliche Variable (8-Bit) geschrieben und wieder gelesen, was das High-Byte der Kopie nullt. Aber wozu sollte man den gewünschten Überlauf "hintricksen"? Code zu schreiben, der sich bei einem signed Wert auf einen bestimmten Überlauf verlässt, ist böse, denn wie gesagt, ein solcher Überlauf ist undefiniert.
    MfG
    Stefan

  5. #15
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo zusammen.

    Na M1.R, da hast du ja was grauenvoll teuflisches entdeckt .

    Ich habe mal alle Varianten zu folgendem ausprobiert mit Optimizermode "-Os" (Größe): (Versionen: avr-gcc (GCC) 4.1.2 (WinAVR 20070525))
    -- Als Variable
    int8_t a=0;
    char a=0;

    -- Als Funktion
    usart_put_int (a);
    usart_put_int ((int8_t) a);
    usart_put_int8_t (a);

    -- Als Rechnung
    a=a+1;
    a+=1;
    a++;

    Es gibt nur genau eine Funktion, die zu jeder Variablen/Rechnungs-Kombination das richtige Ergebnis liefert.
    ==> Das ist die Funktion usart_put_int8_t() mit dem Parametertyp int8_t

    - Das casten hatte nichts gebracht und lieferte beim a++ genau das gleiche falsche Ergebnis.
    - Zu jeder anderen Variablen/Funktions-Kombination, also eigentlich mit falschem Parametertyp, hatte es keinerlei Warning vom Compiler gegeben. Auch dann nicht, wenn alle Funktionen als Prototypen angegeben waren.
    - In allen Fällen wurde die Variable a als 16-Bit-Zahl immer in 2 Registern gehalten.

    Hier der kommentierte Output vom Compiler im Fehlerfall mit a++:
    Code:
    Variante 03: int8_t a++;
       int8_t a=0;
     158:	c0 e0       	ldi	r28, 0x00	; 0  <<== Byte 1 für a
     15a:	d0 e0       	ldi	r29, 0x00	; 0  <<== Byte 2 für a
          usart_put_int (a);
     15c:	ce 01       	movw	r24, r28        <<== Ein WORT wird bewegt
     15e:	c6 df       	rcall	.-116    	; 0xec <usart_put_int>
          a++;
     166:	21 96       	adiw	r28, 0x01	; 1 <<== Ein WORT wird in a addiert
    Hier der kommentierte Output vom Compiler im zufällig funktionierenden Fall mit a=a+1:
    Code:
    Variante 01: int8_t a=a+1
       int8_t a=0;
     158:	c0 e0       	ldi	r28, 0x00	; 0  <<== Byte 1 für a
     15a:	d0 e0       	ldi	r29, 0x00	; 0  <<== Byte 2 für a
          usart_put_int (a);
     15c:	8c 2f       	mov	r24, r28         <<== EIN Byte von a für Parameter
     15e:	99 27       	eor	r25, r25         <<== Vorbelegung Byte 2 für Parameter
     160:	87 fd       	sbrc	r24, 7          <<== Vorzeichen Low-Byte a prüfen
     162:	90 95       	com	r25              <<== Vorzeichen vom Parameter auf - setzen
     164:	c3 df       	rcall	.-122    	; 0xec <usart_put_int>
          a=a+1;
     16c:	21 96       	adiw	r28, 0x01	; 1 <<== Ein WORT wird in a addiert

    Weiterer Versuch mit:
    volatile int8_t a=0;

    Nur jetzt wird die Variable als ein Byte im Speicher gehalten. Das 2.te Byte zum Aufrufen der INT-Parameter-Funktion wird immer mit korrektem Vorzeichen erzeugt.
    - Soll heissen: Es kommt immer das richtige Ergebnis zustande.


    Es bleibt: Parameter müssen passen.
    Es verwundert: Kein Warning vom Compiler.
    Es staunt, grüßt und trinkt nun ein Bier:

    Sternthaler

    P.S.: Ein Versuch, so wie von Radbruch, dass alle Varianten in einem Programm getestet werden, hat vollkommen andere Verhältnisse gebracht.
    Selbst mehrere Variablen mit unterschiedlichen Startwerten konnte den Optimierer meistens nicht dazu bewegen nicht doch nur immer eine Variable zu erzeugen.
    Bei Radbruch wird die "falsche" Variable b wegoptimiert.

    Und dann wäre da noch die "fähige" Funktion:
    void usart_put_int8_t (int8_t wert)
    {
    usart_put_int ((int)wert);
    }
    Lieber Asuro programieren als arbeiten gehen.

  6. #16
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von Sternthaler
    Es gibt nur genau eine Funktion, die zu jeder Variablen/Rechnungs-Kombination das richtige Ergebnis liefert.
    ...
    - Das casten hatte nichts gebracht und lieferte beim a++ genau das gleiche falsche Ergebnis.
    Nur weil das Ergebnis und die Vorgehensweise des Compilers nicht deinen Erwartungen entsprechen, ist das nicht automatisch fehlerhaft. In diesem Fall liegt der Fehler einzig in deinen Vorstellungen, der Compiler verhält sich völlig korrekt.
    Ich wiederhole es gerne nochmal: der Überlauf eines vorzeichenbehafteten Integers wird vom C-Standard ausdrücklich als "undefined" festgelegt. Das einzige, was hier also fehlerhaft ist, ist der C-Code, weil er einen solchen Überlauf verursacht.

    - Zu jeder anderen Variablen/Funktions-Kombination, also eigentlich mit falschem Parametertyp, hatte es keinerlei Warning vom Compiler gegeben. Auch dann nicht, wenn alle Funktionen als Prototypen angegeben waren.
    Wovor sollte da denn auch gewarnt werden? Die Übergabe eines kleineren Integers, als eigentlich von der Funktion erwartet, ist ausdrücklich erlaubt (impliziter Cast). Und von diesem Feature wird auch reger Gebrauch gemacht (oft unbewusst). Es dürfte kaum ein (nicht triviales) Programm geben, in dem das nicht vorkommt.

    Es bleibt: Parameter müssen passen.
    Was tatsächlich bleibt, ist die Tatsache, dass das Ergebnis aus der Kombination "erlaubter impliziter Cast" und "provozieren eines nicht erlaubten signed Overflows" hier manchen verwundern mag, es aber kein Fehler des Compilers ist.
    MfG
    Stefan

  7. #17
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Zitat Zitat von sternst
    Mir ist nicht ganz klar, worum es dir hier überhaupt geht.
    Es geht darum:
    Wenn Variable int8_t a mit a=a+1 hochgezählt wird sieht die Ausgabe wie erwartet so aus:
    ich bin verwirrt!
    Lieber Asuro programieren als arbeiten gehen.

  8. #18
    Erfahrener Benutzer Roboter Experte Avatar von sternst
    Registriert seit
    07.07.2008
    Beiträge
    672
    Zitat Zitat von Sternthaler
    Es geht darum:
    Wenn Variable int8_t a mit a=a+1 hochgezählt wird sieht die Ausgabe wie erwartet so aus:
    ich bin verwirrt!
    Und was willst du mir damit jetzt sagen? Dass es dich verwirrt, dass mit unterschiedlichem Code nicht immer das selbe unerwartete Ergebnis entsteht?
    "undefiniert" heißt "alles Mögliche kann passieren". Das schließt auch mit ein, dass nach einer kleinen Änderung am Code das Ergebnis auf einmal ganz anders aussieht.
    MfG
    Stefan

Seite 2 von 2 ErsteErste 12

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test