Alexander S. schrieb:> gcc -Wall -pedantic -ansi -o add_char_overflow add_char_overflow.c
Auch wenn's jetzt in dem Fall keine Rolle spielt, solltest du mal deine
Optionen updaten. -ansi führt dazu, dass der Compiler auf das 35 Jahre
alte ANSI-C zurückschaltet.
Rolf M. schrieb:> -ansi führt dazu, dass der Compiler auf das 35 Jahre alte ANSI-C> zurückschaltet.
Wo ist da der Vorteil? Die Erklärung hast du offen gelassen.
900ss schrieb:> Wo ist da der Vorteil?
Der Compiler würde auch meine Programme mögen ;) mit -ansi geht
garnichts:
- error: C++ style comments are not allowed in ISO C90
- error: 'for' loop initial declarations are only allowed in C99 or C11
mode
- warning: ISO C does not support '__FUNCTION__' predefined identifier
- warning: anonymous variadic macros were introduced in C99
- warning: comma at end of enumerator list
usw. Demnächst gibt's noch Binary Constants und falltgrough und noreturn
und und
C11: https://open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
C23: https://open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf
900ss schrieb:> Rolf M. schrieb:>> -ansi führt dazu, dass der Compiler auf das 35 Jahre alte ANSI-C>> zurückschaltet.>> Wo ist da der Vorteil? Die Erklärung hast du offen gelassen.
Na dass eben alle Features, die der Sprache in den letzten 35 Jahren
hinzugefügt wurden, genutzt werden können. "Bauform" hat ja schon ein
paar davon gelistet. Wobei gcc manche auch mit -ansi fälschlicherweise
durchlässt, wie z.B. bool oder stdint.h, die es in C89 eigentlich nicht
gibt.
Alexander S. schrieb:> Im Nachhinein habe ich eine> Vermutung warum das Ergebnis bei a + b anders ist als bei c.
Da braucht man nichts zu vermuten.
Alle Berechnungen erfolgen immer so, als wären sie mindestens int. Und
auch printf(%d) erwartet int, d.h. bei Bedarf erfolgt eine Erweiterung
auf int.
Allein die Zuweisung auf c schneidet das höherwertige Byte wieder ab.
Rolf M. schrieb:> 900ss schrieb:>> Rolf M. schrieb:>>> -ansi führt dazu, dass der Compiler auf das 35 Jahre alte ANSI-C>>> zurückschaltet.>>>> Wo ist da der Vorteil? Die Erklärung hast du offen gelassen.>> Na dass eben alle Features, die der Sprache in den letzten 35 Jahren> hinzugefügt wurden, genutzt werden können. "Bauform" hat ja schon ein> paar davon gelistet. Wobei gcc manche auch mit -ansi fälschlicherweise> durchlässt, wie z.B. bool oder stdint.h, die es in C89 eigentlich nicht> gibt.
Ach shit, ich hatte das genau anders verstanden. Ich hatte es erst so
verstanden dass er -ansi nutzen soll und kratzte mich am Kopf und fragte
mich... äh? Dann geht ja "nichts" mehr :)
Aber eben habe ich gesehen, dass du eigentlich wolltest, dass er -ansi
aus seinen angegebenen Optionen streicht. Ich hatte die Option irgendwie
übersehen.
Bauform hat ja schöne Beispiele gebracht.
Ich nutze mal eine IDE im Job, die -ansi default setze wenn man ein
Projekt erzeugte. Das war das erste was ich gestrichen habe.
Mir ist das Verhalten in so weit klar, als das bei C das Verhalten bei
underflow und overflow von signed char oder signed int, im Gegensatz zu
unsigned char oder unsigned int, nicht definiert ist.
Alexander S. schrieb:> Mir ist das Verhalten in so weit klar, als das bei C das Verhalten bei> underflow und overflow von signed char oder signed int, im Gegensatz zu> unsigned char oder unsigned int, nicht definiert ist.
Bis auf das
> --c;
und das
> ++c;
ist alles wohldefiniert.
Alexander S. schrieb:> Rolf M. schrieb:>> ist alles wohldefiniert.>> Nicht für signed int.
Richtig, aber der Wertebereich von signed int ist auf jeden Fall groß
genug, um den von dir verwendeten Zahlenbereich abzudecken, daher gibt
es hier außer bei ++ und -- kein Problem.
Denn wie oben schon erwähnt wurde:
Peter D. schrieb:> Alle Berechnungen erfolgen immer so, als wären sie mindestens int.
Das nennt sich "integer promotion". Das heißt, dass hier:
Alexander S. schrieb:> c - 1
c erst mal auf int erweitert wird und dann die Berechnung mit dem Typ
durchgeführt wird. Das Ergebnis ist natürlich dann auch vom Typ int.
Somit kann da nix überlaufen, weil der Wertebereich von int groß genug
ist, um das Ergebnis aufzunehmen.
Alexander S. schrieb:> c - (signed char) 1
Hier ist es das gleiche. Dein Cast ändert daran nichts. Es wird durch
ihn die 1 lediglich erst nach signed char konvertiert, bevor sie dann
sofort wieder (wie die Variable c) nach int konvertiert wird. Die
Berechnung erfolgt dann auch wieder mit Typ int.
Lediglich bei --c und ++c gibt es ein Problem, weil da das Ergebnis ja
wieder nach c zurückgeschrieben wird, das aber nicht groß genug dafür
ist.
Weil c in beiden Fällen uninitialisiert ist und dein Code dadurch
undefiniertes Verhalten auslöst. Aber ich vermute, du wolltest hier c
mit SCHAR_MAX initialisieren. Dann hast du aber trotzdem undefiniertes
Verhalten, weil eben der Wertebereich von c nicht mehr ausreicht.
Laut C-Standard ist ++c äquivalent zu c+=1 ("The expression ++E is
equivalent to (E+=1), where the value 1 is of the appropriate type.")
und das wiederum ist (mit der Ausnahme dass c nur einmal evaluiert wird)
äquivalent zu c = c + 1. ("A compound assignment of the form E1 op= E2
is equivalent to the simple assignment expression E1 = E1 op (E2),
except that the lvalue E1 is evaluated only once, and with respect to an
indeterminately sequenced function call, the operation of a compound
assignment is a single evaluation")
Da das Verhalten in diesem Fall undefiniert ist, muss das Ergebnis aber
nicht gleich sein.
Alexander S. schrieb:> der entscheidende Punkt ist wohl, dass man zwischensigned char c;> c = SCHAR_MAX;> printf("%d", c + 1);>> undsigned char c;> c = SCHAR_MAX;> c = c + 1;> printf("%d", c);>> unterscheiden muss. Im ersten Fall ist der Wertebereich int und im> zweiten Fall signed char.
Ja, weil du im zweiten Fall das Ergebnis nach c zurückschreibst, das vom
Typ signed char ist, in den es aber nicht reinpasst. Im ersten Fall
dagegen verarbeitest du das Ergebnis der Addition direkt als int weiter.
Somit läuft da nichts über. Würdest du schreiben:
1
intd=c+1:
dann wäre das Ergebnis das gleiche wie im ersten Fall.