PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] gemischter Vergleich mit signed und unsigned



Siro
24.11.2011, 15:41
Hallo zusammen,
daß es ein Problem beim Vergleichen mit signed und unsigned Typen gibt ist mir inzwischen bekannt.
Wenn ein Wert als unsigned definiert wird und der zweite als signed, wird wohl generell mit unsigned verglichen,
so habe ich es zumindest bisher verstanden, bzw. wurde mir das hier im Forum mal so erläutert.
Das scheint aber nicht immer so zu sein, wie mir mein Code grade zeigt. Das ist Typabhängig, zumindest bei meinem Compiler: IAR Embedded Workbench ???


/*----------------------------------------*/
signed short istWert;
unsigned short sollWert;
int dummy;

int main(void)
{ U32 time;

istWert = -1;
sollWert = 12;
if (istWert < sollWert)
{
dummy = 1; /* hier geht es */
}
}
/*----------------------------------------*/
signed int istWert;
unsigned int sollWert;
int dummy;

int main(void)
{ U32 time;

istWert = -1;
sollWert = 12;
if (istWert < sollWert)
{
dummy = 1; /* hier geht es NICHT !!!!! */
}
}


Anscheinend habe ich es doch noch nicht richtig verstanden ?.
Aber zum Glück habe ich Euch...und freue mich über eine Antwort...
Siro

sternst
24.11.2011, 18:25
Aus deinem Beitrag kann ich schließen, dass beim IAR der Typ short kleiner ist als der Typ int.

Und jetzt überlege mal, warum ich diesen Schluss ziehen kann, denn diese Überlegung enthält dann auch die Antwort auf deine Frage.

Siro
24.11.2011, 23:10
Hallo sternst,
also mit deiner Vermutung daß der Short kleiner ist als der Int, gebe ich Dir erstmal recht.


Aber nun werde ich mal versuchen was mir das sagt:

Der Short hat in meinem Falle eine Bitbreite von 16.
Demnach bei einem "signed short " einen Wertebereich von -32768 bis+32767

Der int hat 32 Bits also bei einem signed int -2147483648 bis +2147483647

-1 wird in signed 16 Bit als 0xFFFF dargestellt.
-1 mit 32 Bit ist 0xFFFFFFFF

+12 ist in 16 Bit 0x000C
+12 in 32 Bit ist 0x00000000C

jetzt die Abfrage
if (0xFFFF < 0x000C) würde FALSE ergeben, wenn ich die Werte ohne Vorzeichen behandele,
denn 65535 ist NICHT kleiner als 12
TRUE wenn ich die Vorzeichen beachte, weil -1 nunmal kleiner ist als +12
Das Ergebnis des Compilers ist richtig, er liefert TRUE, hat also anscheinend das Vorzeichen richtig beachtet.
Würde er ohne Vorzeichen arbeiten wäre das Ergebnis FALSE weil 65535 NICHT kleiner ist als 12
Also ist das Ergenis einwandfrei bei 16 Bit Operationen.

nun der Fall für 32 Bit
if (0xFFFFFFFF < 0x000000C) würde FALSE ergeben, wenn ich die Werte ohne Vorzeichen behandele.
TRUE wenn ich die Vorzeichen beachte.
Das Ergebnis des Compilers ist aber FALSCH, er behandelt das Vorzeichen anscheinend nicht
und deshalb ist 4294967296 nicht kleiner als 12 und damit liefert er FALSE, was halt FALSCH ist.

Im Prinzip ist es mir eagal ob er die Mischung von signed und unsigned nicht hinbekommt, dann aber bitte konsequent
immer falsch, aber bitte nicht Bitanzahl abhängig.

Mir ist der Arbeitsweise hier leider nicht einleuchtend. Vielleicht denke ich immer noch zu viel in Assembler ???

Eigentlich spielt das doch gar keine Rolle wie viele Bits ich für einen signed bzw. unsigned benutze. Dafür
gibt es doch eine Rechenvorschrift, die hier anscheinend nicht immer identisch "verhackstückt" wird.

Ich verstehe es wirklich nicht,
komme nicht dahinter,
Siro

sternst
24.11.2011, 23:37
Im Prinzip ist es mir eagal ob er die Mischung von signed und unsigned nicht hinbekommt, dann aber bitte konsequent
immer falsch, aber bitte nicht Bitanzahl abhängig. Das Ergebnis des gemischten Vergleichs ist nicht von der Bitanzahl abhängig. Der springende Punkt ist, dass bei dem Vergleich mit den short Variablen gar kein gemischter Vergleich stattfindet, sondern ein reiner signed/signed-Vergleich. Warum? int-Promotion!

Siro
25.11.2011, 07:54
Ersteinmal guten Morgen sternst,
wuste ich doch, daß ich mal wieder was nicht wuste

Du hast mal wieder den Nagel auf den .....
Das Zauberwort "Integer Promotion" habe ich noch nie gehört und google grade ein bischen.
Habs noch nicht ganz verstanden, bin aber auf dem besten Wege dahin. Zumindest liegt da wohl die Antwort auf meine Frage.
Das ist aber eine böse Falle, für Programmierer wie mich, mit relativ wenig Erfahrungen in der Progrmmiersprache C.
Bedanke mich ganz herzlich.
Siro

Siro
25.11.2011, 09:56
So, ich hoffe, ich habe es jetzt richtig verstanden. Eine Rückmeldung wär nett, "Jo, stimmt "oder "völliger Blödsinn"

Ich versuche mal das Problem zu beschreiben, so wie ich es jetzt verstanden habe:

Der Compiler möchte einen Vergleich zweier Zahlen durchführen.


30.11.2011 Siro ist schlauer geworden......
!!!!!! was jetzt folgt ist völliger Blödsinn und ich möchte nicht, daß Ihr nur annähernd glaubt was ich hier vorher interpretiert habe.
Ich lasse es aber der Vollständigkeit halber trotzdem stehen.

signed int a;
unsigned int b;
if (a < b) ...


Wir stellen ihm einen signed int 32 Bit Wert zur Verfügung „a“. Das ist also ein 31 Bit Wert für die Zahlendarstellung und ein zusätzliches Bit für das Vorzeichen. Dann haben wir einen unsigned Wert „b“auch 32 Bits, dieser hat aber KEIN Vorzeichen, hier werden also alle 32 Bits für die Zahlendarstellung benötigt. Damit der Compiler einen Vergleich durchführen kann, versucht er zunächst beide Werte auf die gleiche Anzahl Bits zu „erweitern“. Da also Wert „b“ 32 Bits ohne Vorzeichen hat und Wert „a“ ein Vorzeichen besitzt, benötigen wir mindestens einen Datentyp mit 33 Bits. 32 Bits für die Zahlendarstellung und ein Bit für das Vorzeichen. Das geht aber nicht, da der Datentyp „int“ in meinem Falle mit 32 Bit schon voll ausgelastet ist. Was also tun ??? Man hat sich anscheinend mal dazu entschieden, das Vorzeichen wegzulassen, damit der 32 Bit Zahlenwert in den „int“ rein passt. Das Vorzeichen wird also nun für die eigentliche Zahlendarstellung benutzt und schwups wird aus einem signed int ein unsigned int. Was natürlich Auswirkungen auf das Ergebnis hat. Der Vergleich schlägt fehl. Entscheidend ist die interne Darstellungsweise des Datentyps „int“ und dieser ist je nach verwendeten Compiler bzw. verwendeter Zielhardware unterschiedlich. Kann also 8,16,32 oder sogar 64 Bit breit sein. Also kurz gesagt, der Compiler versucht den nächst „breiteren“ (grösseren) Datentyp zu wählen in den beide Werte komplett mit Vorzeichen hineinpassen. Bei meinem Prozessor mit „int“ = 32 Bit kann er also ohne Probleme und ohne Datenverlust einen unsigned short (16 Bit) in einen signed int (32) Bit wandeln, was er aber nicht kann, ist eine 32 Bit unsigned int ohne Datenverlust in einen int mit 32 Bit plus Vorzeichenbit wandeln. Also verschwindet das Vorzeichen und der Wert wird unweigerlich als unsigned interpretiert obwohl er eigentlich signed sein sollte.


Siro.

sternst
25.11.2011, 11:31
Eine Rückmeldung wär nett, "Jo, stimmt "oder "völliger Blödsinn"Ich weiß gar nicht so recht, wo ich das jetzt einordnen soll. Das stimmt irgendwie alles so halb. Was allerdings überhaupt nicht stimmt, ist der Grund warum der Compiler aus den short für den Vergleich int macht. Mit den Vorzeichen und gemischten Vergleichen hat das nämlich nichts zu tun.

Siro
25.11.2011, 12:15
Schade eigentlich, für mich klang das sehr plausibel.
Dann sollte ich den Text mal lieber wieder löschen, sonst glaubt das noch jemand so.
Siro

radbruch
25.11.2011, 12:42
Hallo

Laß den Text mal besser stehen. Auch wenn's noch nicht stimmt würde der Thread durchs Löschen zu sehr zerrissen. Nettes Grundlagenthema finde ich übrigends.

Gruß

mic

sternst
25.11.2011, 14:36
Siro,
du solltest dir wirklich mal ernsthaft Gedanken um dein grundsätzliches Vorgehen machen. Ständig probierst du nur rum und ziehst dann aus deinen Beobachtungen deine eigenen Schlüsse, wie es sein könnte. Man kann eine Programmiersprache auf die Art nicht richtig lernen. Zum einen können diese Schlüsse schlicht falsch sein (was sie ja auch schon mehrfach waren), zum anderen hat jede Sprache irgendwelche Grundregeln, die man sich fast unmöglich auf diese Art selbst "erarbeiten" kann. Und warum sollte man das auch überhaupt erst probieren, wo doch der richtige Weg nicht nur zuverlässiger, sondern auch schneller ist. In der Zeit, die du bisher mit deinen "Eigenforschungen" verbracht hast, hättest du mit Sicherheit auch locker ein C-Buch sorgfältig durcharbeiten können. "Herumprobieren" ist höchstens sinnvoll, um zu überprüfen, ob man alles richtig verstanden hat. Und wenn ich dann noch daran denke, dass es bei dir nicht um eine Freizeitbeschäftigung geht, sondern um deinen Job ....


Zum Thema:

'<' ist ein normaler Operator wie auch '+', '-', etc. Das bedeutet, dass für ihn auch die Integer-Promotion-Rules gelten. Im wesentlichen ist das:
1) Die Typen der Operanden werden auf die selbe Größe gebracht. Der Größte "gibt den Takt vor", mindestens aber int.
2) Haben die Typen bereits die selbe Größe, aber eine unterschiedliche Signedness, wird in unsigned gerechnet.

Bei den int-Operanden sorgt 2) für das unerwartete Ergebnis.
Bei den short-Operanden spielt 2) keine Rolle mehr, nachdem 1) angewendet wurde.

Siro
25.11.2011, 15:26
Naja, hättest ruhig sagen können, daß es ziemlicher Blödsinn ist, was ich geschrieben habe.
So hätte ich es mir vielleicht gedacht, aber so funktioniert es nunmal nicht.
Also ich versuche es noch einmal und werde jede Aussage separat halten, so könnt Ihr mir ein Sternchen vergeben wenn die Aussage richtig ist.
Ich möchte es ja einfach nur verstehen.

Der Standard Datentyp in "C" ist "int"

Wie groß ein "int" ist, hängt vom System ab.

Es können KEINE, weder logische noch mathematische Operation mit Werten durchgeführt werden, die eine kleinere Rangfolge haben als ein "int".

Die Rangfolge entspricht dem Speicherbedarf. ??? mach ich mal 3 Fragezeichen, ist das so ???

Aus einem char (8 Bit, unabhängig davon ob signed oder unsigned) wird vor einer logischen oder mathematischen Funktion ein "int"

Aus einem short (16 Bit, unabhängig davon ob signed oder unsigned) wird vor einer logischen oder mathematischen Funktion ein "int"
unter der Vorraussetzung, daß der Datentyp "short" eine geringere Rangfolge hat als der "int".

Werden 2 "int" Werte in eine logische oder mathematische Operation verwickelt, wovon einer der beiden ein unsigned ist,
wird der zweite Operand (der eigentlich signed ist) zu einem unsigned.

Habe den Text übrigens vor deinem letzten Beitrag (von sternst) geschrieben. Hab mich den ganzen Tag mit bescchäftigt, sogar den Assembler Code zerpflückt.
Danke nochmal.

Korrektur 30.11.2011
Stimmt irgendwie alles nicht, wie ich grad feststellen muste. Die Beschreibung lässt doch sehr zu wünschen übrig, wie die Integer Promotion funktioniert oder funktionieren sollte.
Rechnen tut er "oftmals" richtig, aber vergleichen geht ständig schief. Das Verhalten wird immer merkwürdiger.......
Hab auch keinen Bock mich weiterhin mit diesem Blödsinn auseinanderzusetzen, zumal mein Controller Vorzeichenrichtig in Hardware vergleichen kann, aber C baut einen derartigen Code herum, daß es nicht mehr funktioniert.
In Assembler läuft es einwandfrei.

Die einzige Möglichkeit welche ich gefunden habe, damit der C-Code wieder richtig funktioniert, ist die explizite Typwandlung vor dem Vergleich. Ansonsten ist das Ergebnis "UNDEFINIERT"
bzw. Compiler (Prozessor) spezifisch, also:

if (signed(a) > signed (b)) ......




Siro

Siro
07.12.2011, 21:33
geschlossen.