mr.chip wrote:
> Naja...was passiert eigentlich genau, wenn ich einen int8_t in einen
> uint8_t caste? Wird da aus (beispielsweise) einem signed 120 immer noch
> ein unsigned 120? (Meine Simulationsergebnisse mit AVR Studio
> widersprechen dem eher, wobei ich noch nicht ganz verstanden habe, wo
> und wann Probleme auftreten.)
ZUnächst mal musst du berücksichtigen, dass bei derartigen
casts (wenn sich also nur die Signedness ändert) sich am
Bit-Pattern überhaupt nichts ändert. Es ist lediglich die
Interpretation dieses Bitpatterns die sich ändert.
Lass mich mal einen hypothetischen 4 Bit-Datentyp einführen.
Die Prinzipien sind bei größeren Datentypen absolut dieselben
nur hab ich jetzt weniger Tipparbeit :-)
Welche Bit-Pattern sind mit 4 Bit überhaupt möglich
0000 0 0100 4 1000 8 1100 12
0001 1 0101 5 1001 9 1101 13
0010 2 0110 6 1010 10 1110 14
0011 3 0111 7 1011 11 1111 15
Ich habe neben jedes Bit-Pattern auch noch die Dezimalzahl
dazugeschrieben, die diesem Bit-Pattern entspricht.
Das wären die unsigned Werte. Beginnend bei 0 wird einfach
durchgezählt, bis die Darstellungsmöglichkeiten des Bit-Patterns
aufgebraucht sind. Mit 4 Bit sind 16 verschiedene (2 hoch 4)
Zustände möglich. Demzufolge kann man mit 4 Bit die unsigned
Werte 0 bis 15 darstellen.
Wie kommt da jetzt das Vorzeichen für signed Werte ins Spiel.
Zunächst mal muss man festhalten, dass es im Rechner so was
wie ein Vorzeichen nicht wirklich gibt. Was es gibt ist eine
Konvention. Und zwar vereinbart man zb. dass wenn das am weitesten
links stehende Bit 0 ist, dass man dann die Zahl als positive
Zahl ansieht, während man die Zahl als negativ ansieht wenn das
am weitesten links stehende Bit (das sog. Most Signifikant Bit
oder MSB) eine 1 darstellt.
zb. könnte man die 16 möglichen Zustände dann auch so inter-
pretieren:
0000 +0 0100 +4 1000 -0 1100 -4
0001 +1 0101 +5 1001 -1 1101 -5
0010 +2 0110 +6 1010 -2 1110 -6
0011 +3 0111 +7 1011 -3 1111 -7
Wäre eine Möglichkeit. Man könnte auch so interpretieren:
0000 +0 0100 +4 1000 -7 1100 -3
0001 +1 0101 +5 1001 -6 1101 -2
0010 +2 0110 +6 1010 -5 1110 -1
0011 +3 0111 +7 1011 -4 1111 -0
Du siehst schon: Während bei den positiven Zahlen es relativ
naheliegend ist, wie ein Bitpattern interpretiert werden soll,
ist das bei den negativen weit weniger intuitiv.
Aber welche Interpretation soll man wählen? Was ist sinnvoll.
Nun, sinnvoll ist ganz sicher eine Interpretation, bei der
man in der tatsächlichen Rechnerei keine Probleme hat.
Und genau da kommt jetzt das 2-er Komplement ins Spiel.
Das 2-er Komplement besagt, dass man eine Zahl negiert, indem
alle Bits umgedreht werden (aus 0 wird 1, aus 1 wird 0) und dann
noch 1 addiert wird.
Beispiel: aus dem Bitpattern 0110 (welches der Zahl 6 entspricht)
wird so:
0110 ursprüngliche Zahl
1001 alle Bits umgedreht
1010 und noch 1 dazugezählt.
1010 soll also das Bit-Pattern für -6 sein (weil ja die ursprüngliche
Zahl 6 war). Macht man das für alle Bit-Pattern so ergibt sich
0000 +0 0100 +4 1000 -8 1100 -4
0001 +1 0101 +5 1001 -7 1101 -3
0010 +2 0110 +6 1010 -6 1110 -2
0011 +3 0111 +7 1011 -5 1111 -1
Wieder zeigt sich, dass bei allen negativen Zahlen das MSB 1 ist,
und somit quasi die Anzeige 'Ich bin eine negative Zahl' darstellt.
Das 2-er Komplement hat die angenehme Eigenschaft, dass es in
beide Richtungen funktioniert. Nehmen wir das Bit Pattern
1011. Da das MSB 1 ist, handelt es sich um eine negative Zahl.
Um zu wissen welche, bestimmen wir einfach die dazugehörige
positive Zahl:
Bits umdrehen +1
1011 -> 0100 -> 0101
0101 ist die Zahl 5. Also ist 1011 das Bit-Pattern für -5
Damit nicht genug. Das 2-er Komplement sorgt auch dafür, dass
man bei Additionen sich keine Gedanken über das Vorzeichen machen
muss.
Eine Addition: 4 + -7 erfolgt ganz normal ohne dass man für
die negative Zahl -7 irgendwelche Vorkehrungen treffen muss:
0100
+ 1001
-----
1101
Im Ergebnis ist das MSB gesetzt, das Ergebnis ist also eine negative
Zahl. Welche?
1101 -> 0010 -> 0011
0011 ist dezimal 3. Das Ergebnis ist also -3. Und das ist ja für
4 + -7 offensichtlich korrekt.
Soweit zu signed.
Wenn man jetzt aber die Tabellen für unsigned und signed
mal vergleicht:
unsigned
0000 0 0100 4 1000 8 1100 12
0001 1 0101 5 1001 9 1101 13
0010 2 0110 6 1010 10 1110 14
0011 3 0111 7 1011 11 1111 15
signed
0000 +0 0100 +4 1000 -8 1100 -4
0001 +1 0101 +5 1001 -7 1101 -3
0010 +2 0110 +6 1010 -6 1110 -2
0011 +3 0111 +7 1011 -5 1111 -1
so sieht man, dass sie für alle (signed) positiven Zahl übereinstimmen.
Signed 6 hat das gleiche Bit-Muster wie unsiged 6. Lediglich dann
wenn das MSB gesetzt ist, gibt es Unterschiede: Im unsigned Fall
handelt es sich dann um eine Zahl, die mit signed Mitteln nicht
mehr darstellbar wäre (weil dazu ja dieses eine Bit notwendig
wäre, welches die Rolle des Vorzeichens spielt). Diese Bit-Muster
werden dann im signed Fall einfach anders interpretiert.
Zurück zu deinem Beispiel und 8-Bit Zahlen:
Das Bit Muster für unsigned 120 lautet: 01111000
Da hier das MSB nicht gesetzt ist, wäre das also auch als
signed Zahl die Zahl +120
Was ist mit der unsigned Zahl 240.
Das zugehörige Bitmuster lautet: 11110000
Da hier das MSB gesetzt ist, kannst du darauf wetten, dass diese
Bit-Muster, wenn wir es als signed Zahl betrachten, nicht mehr
240 ergeben wird. MSB = 1 bedeutet ja: es handelt sich um
eine neagtive Zahl. Aber um welche?
2-er Komplement anwenden:
11110000 -> 00001111 -> 00010000
und das entspricht wiederum der Zahl 16. Also ist 11110000 das
Bitmuster der Zahl -16, wenn dieses Bitmuster als signed Zahl
interpretiert wird. Tue ich das nicht, und möchte ich dieses
Bitmuster als unsigned sehen, dann entspricht es der Zahl 240.
signed und unsigned sind also nur 2 verschiedene Betrachtungsweisen
desselben Bitmusters. Wechsle ich von einem zum anderen, dann
ändert sich am Bitmuster selbst überhaupt nichts. Lediglich die
Aussage, die dieses Bitmuster über seine Zahl macht, ändert sich.