Zu finden unter "integer promotion rules".
Hier: Da beide Seiten in ein "int" passen, wird das Ergebnis so
ausfallen, als würden beide Seiten in "int" umgewandelt.
In diesem Fall eines einfachen "==" ohne Rechnung links wie rechts ist
das allerdings einerlei.
A. K. schrieb:
> In diesem Fall eines einfachen "==" ohne Rechnung links wie rechts ist> das allerdings einerlei.
Nein, ist es nicht. var2 wird vorzeichenerweitert in einen int
gewandelt, var1 nicht (weil sie unsigned ist).
6.3 Conversions
6.3.1 Arithmetic operands
6.3.1.1 Boolean, characters, and integers
(Ziemlich abstrakte Abhandlung von "rank", am Ende:)
If an int can represent all values of the original type, the value
is converted to an int; otherwise, it is converted to an unsigned
int. [...]
Damit ist klar, dass var1 als Bitmuster in den int-Wert übernommen
wird, denn int kann alle Werte eines uint8_t abbilden. Damit ist
auch klar, dass var2 sign-extended übernommen werden muss, denn
ein Wert von bspw. -1 (0xFF als int8_t) muss weiterhin -1 bleiben
(0xFFFF als int).
Auch noch interessant in dem Zusammenhang, auch wenn es den Fall
hier nicht direkt berührt:
6.3.1.3 Signed and unsigned integers
Jörg Wunsch schrieb:
> Nein, ist es nicht. var2 wird vorzeichenerweitert in einen int> gewandelt, var1 nicht (weil sie unsigned ist).
Stimmt. Genauer gesagt, var2 wird auch in ein "int" gewandelt, aber aber
ohne Vorzeichen, also als positive Zahl verstanden.
Ich hatte da allerdings eher Spielchen wie
var1 == var2 + 1
im Auge gehabt, bei denen in 8- und 16-Bit Rechnung durchaus
verschiedene Ergebnisse rauskommen.
Hallo,
ich hätte da auch mal eine Frage.
Ich habe in vielen uC-Programmen gesehen dass unsigned int verwendet
wird.
Wieso spielt es eine so große Rolle ob ich int oder unsigned int
verwende.
MfG
..... schrieb:
> Wieso spielt es eine so große Rolle ob ich int oder unsigned int> verwende.
Einige 8-Bit Mikrocontroller tun sich mit diversen vorzeichenbehafteten
Operationen wie Vergleichen und Rechtsschieben etwas schwer (z.B. 8051
und PIC).
Ich versuche gerade die Integer Promotion Regeln abzuleiten. Ist
folgendes richtig ?
Für einen Typ T in einem Ausdruck gilt:
(1) Wenn sizeof(T) >= sizeof(int): Keine Änderung von T
(2) Wenn sizeof(T) < sizeof(int):
(a) unsigned(T): T wird zu "unsigned int" promoted
(b) signed(T): T wird zu "int" promoted
Ist dies vollständig und deckt auch alle Regeln ab?
Viele Grüße
Klaus
klaus schrieb:
> (1) Wenn sizeof(T) >= sizeof(int): Keine Änderung von T
Bedenke, dass Operatoren auch mal 2 Operanden haben.
> (2) Wenn sizeof(T) < sizeof(int):> (a) unsigned(T): T wird zu "unsigned int" promoted> (b) signed(T): T wird zu "int" promoted
(2) Wenn sizeof(T) < sizeof(int): T wird zu "int" promoted
2a stimmt nicht. Wenn T unsigned ist und sein Wertebereich komplett
durch ein int (also signed) abgedeckt werden kann (was ja in der Regel
der Fall ist), dann wird es zu int promotet.
Davon abgesehen spielen natürlich auch noch die Typen der restlichen
Operanden eine Rolle. Denn für die meisten Operatoren gilt, dass alle
Operanden den gleichen Typ haben müssen. Deshalb ist keine deiner Regeln
allgemein in jedem Fall gültig.
> 2a stimmt nicht. Wenn T unsigned ist und und sein Wertebereich komplett> durch ein int (also signed) abgedeckt werden kann (was ja in der Regel> der Fall ist), dann wird es zu int promotet
Nach meinem Verständnis geht das Gegenteil aus dem obigen Beispiel
hervor:
1
int main()
2
{
3
uint8_t i;
4
5
i = -1;
6
if( i == -1 )
7
printf( "stimmt\n" );
8
else
9
printf( "stimmt nicht\n" );
10
}
Wenn hier i zu einem "int" promoted würde, also signed wäre, gäbe es ja
hier keine Überraschungen, da es vorzeichenrichtig erweitert würde (also
-1 wäre). Im anderen Fall würde es von 0xFF zu 0x000000FF erweitert und
mit 0xFFFFFFFF verglichen (bei sizeof(int) = 4).
klaus schrieb:
> Wenn hier i zu einem "int" promoted würde, also signed wäre, gäbe es ja> hier keine Überraschungen, da es vorzeichenrichtig erweitert würde
"i" ist vorzeichenlos, dessen Wertebereich von 0..255 lässt sich durch
"int" abdecken. Die Erweiterung selbst ist vorzeichenlos, aber nicht das
Ergebnis der Erweiterung. Also kommt sehr wohl
if (255 == -1)
dabei raus.
klaus schrieb:
> Wenn hier i zu einem "int" promoted würde, also signed wäre, gäbe es ja> hier keine Überraschungen, da es vorzeichenrichtig erweitert würde
i ist unsigned, enthält also eigentlich 255 (und eben nicht -1) und wird
daher vorzeichenrichtig zu 0x00FF erweitert, also ebenfalls 255.
Tip: Rein formal müsste ein Compiler bei
i = -1;
eine Warnung ausspucken, weil der Operand nicht ins Ziel passt.
Allerdings würden viele bestehenden Programme in Warnungen absaufen,
weshalb sowas rasch wieder rausfliegt oder abgeschaltet wird.
> Wenn hier i zu einem "int" promoted würde, also signed wäre,
i ist aber nicht signed. i ist unsigned
> gäbe es ja hier keine Überraschungen, da es vorzeichenrichtig> erweitert würde (also -1 wäre).
Der Dreh besteht ja gerade darin, dass i eben nicht signed ist. i
enthält 255 (wenn wir mal 2-er Komplement annehmen)
Du machst den Fehler, der interessanterweise so häufig gemacht wird: Der
Zieldatentyp hat mit der Auswahl der Operation nichts zu tun. Die
Promotion ist hier von unsigned char nach int. Wie diese Promotion
gemacht wird (ob Vorzeichen berücksichtigt werden muss oder nicht) hängt
einzig und alleine vom Ausgangsdatentyp ab.
Das ist eine der Grundregeln von C. Bei der Auswahl der Operation spielt
der Zieldatentyp nur insofern eine Rolle als er das anzustrebende Ziel
vorgibt. Aber die Details der Operation werden immer nur vom
"Ausgangsmaterial" abgenommen. Insofern kann man sagen: Der Zieldatentyp
spielt bei der Auswahl der Operation keine Rolle. (Für eine Addition
spielt es keine Rolle wo das Ergebnis abgelegt wird)
Deine Regel kann man daher so zusammenfassen:
Alles was kleiner als int ist (egal ob signed oder unsigned) wird zu
int.
Das ist auch eines der Probleme, warum der gcc manchmal mit sanfter
Gewalt zu Optimierungen gezwungen werden muss und sich als
'Universalcompiler' auf Byteebene manchmal schwer tut. Spezialcompiler
für µC nehmen es mit dieser int-Promotion in manchen Bereichen nicht
ganz so genau.
Bin heute etwas schwer von Begriff :-) Es ist doch aber schon so, dass
anhand des Quelldatentypes entschieden wird, was auf Bitebene geschieht
oder?
Beispiel:
1
signed char x = -1
2
unsigned char y = -1
3
4
if (x == -1) // 0xFFFFFFFF == 0xFFFFFFFF bzw. -1 == -1
5
{
6
//...
7
}
8
if (y == -1) // 0x000000FF == 0xFFFFFFFF bzw. 255 == -1
9
{
10
//...
11
}
x und y enthalten ursprünglich auf Bitebene den gleichen Wert. Aber je
nachdem ob der Typ signed oder unsigned ist, erfolgt auf Bitebene eine
andere Behandlung bei der Erweiterung. Denke ich zu "bitorientiert" ?
klaus schrieb:
> x und y enthalten ursprünglich auf Bitebene den gleichen Wert. Aber je> nachdem ob der Typ signed oder unsigned ist, erfolgt auf Bitebene eine> andere Behandlung bei der Erweiterung.
Jetzt hast du es :-)
klaus schrieb:
> x und y enthalten ursprünglich auf Bitebene den gleichen Wert. Aber je> nachdem ob der Typ signed oder unsigned ist, erfolgt auf Bitebene eine> andere Behandlung bei der Erweiterung. Denke ich zu "bitorientiert" ?
Korrekt. Der Datentyp der Quelle entscheidet was geschieht, nicht der
Typ des Ziels.
Die Ausgabe auf
#include <stdio.h>
int main()
{
uint8_t i;
i = -1;
if( i == -1 )
printf( "stimmt\n" );
else
printf( "stimmt nicht\n" );
}
scheint Compilerspezifisch zu sein ...
Bei mir wird stimmt ausgegeben :o
Das würde heissen, je nach Compiler/Entwicklungsumgebung erhalte ich bei
gleichem Code ein anderes Ergebnis ...
comtronic_99 schrieb:> scheint Compilerspezifisch zu sein ...
an und für sich nicht. Da gibt es Regel im C-Standard, die diesen Fall
handhaben.
Welcher Compiler ist das?
Mit welchen Flags rufst du ihn auf?
comtronic_99 schrieb:> scheint Compilerspezifisch zu sein ...
Ein Compiler, der sich an den C Standard hält, darf das nicht. Es gibt
aber C-Compiler für 8-Bit µCs, bei denen "int" 8 Bits breit sein kann.
Dann kommt genau das dabei raus.
Falk Brunner schrieb:>> uint8_t i;>>> i = -1;>> Hier muss der Compiler aber MINDESTENS ne Warung ausgeben.
Der GCC tut das auch, aber nur, wenn man die entsprechende Warnung mit
-Wconversion explizit aktiviert. Nur -Wall und sogar -Wextra sind zu
wenig. Mit -Wconversion kann man nämlich kaum existierenden C-Code
kompilieren, ohne seitenweise Warnungen zu bekommen.
Wenn man genügen Warnungsregister zieht, erhält man diese Meldungen:
1
sutest.c: In function ‘main’:
2
sutest.c:8:3: warning: negative integer implicitly converted to unsigned type [-Wsign-conversion]
3
i = -1;
4
^
5
sutest.c:9:3: warning: comparison is always false due to limited range of data type [-Wtype-limits]
6
if( i == -1 )
7
^
Das sollte eigentlich als Anlass ausreichen, den Code noch einmal
gründlich zu prüfen.
Edit: Beim Schreiben zu lange getrödelt :)
tsakamm schrieb:>> Hier muss der Compiler aber MINDESTENS ne Warung ausgeben.tsakamm schrieb:> @Karl Heinz Buchegger (kbuchegg) (Moderator)>> uint8_t i;>> i = -1;> Hier muss der Compiler aber MINDESTENS ne Warung ausgeben.
Im Frühjahr tuts der meistens nich
Falk Brunner schrieb:> @Karl Heinz Buchegger (kbuchegg) (Moderator)>>> uint8_t i;>>> i = -1;>> Hier muss der Compiler aber MINDESTENS ne Warung ausgeben.
Als Faustregel:
Der Compiler MUSS Errors ausgeben. Die sind vom C-Standard gefordert.
Was er darüber hinaus anwarnt oder nicht anwarnt, entscheidet der
Compilerbauer.
Karl Heinz Buchegger schrieb:> Als Faustregel:>> Der Compiler MUSS Errors ausgeben. Die sind vom C-Standard gefordert.> Was er darüber hinaus anwarnt oder nicht anwarnt, entscheidet der> Compilerbauer.
Ohne es nachzuschauen: Mir war so, daß die Unterscheidung im Standard
gar nicht existiert, und das alles nur "diagnostics" sind.
Die Unterteilung in "error - bricht ab" und "warning - compiliert
weiter" wäre dann Implementierungssache.
Ist dem nicht so?
Stefan Rand schrieb:> Die Unterteilung in "error - bricht ab" und "warning - compiliert> weiter" wäre dann Implementierungssache.
Jein.
“The intent is that an implementation should identify the nature of,
and where possible localize, each violation. Of course, an
implementation is free to produce any number of diagnostics as long as
a valid program is still correctly translated. It may also
successfully translate an invalid program.”
Also letztlich ist die einzige Forderung, dass ein gültiger Quelltext
sauber compiliert wird.
Lediglich für die Direktive #error ist zwingend ein Abbruch der
Übersetzung mit Fehlerstatus gefordert.