Bitweise Invertierung


schiese

Erfahrenes Mitglied
#1
Hallo,

ich habe ein bißchen mit der bitweisen Invertierung rumprobiert und mir ist etwas aufgefallen, das ich nicht verstehe. Der folgende Schnipsel bestimmt die größte positive signed short Zahl:
C++:
unsigned short zahl = 0;
unsigned short zahl2 = ~zahl;
unsigned short zahl3 = zahl2 >> 1;
signed short zahl_negiert_signed = static_cast<signed short>(zahl3);
std::cout << "Zahl: " << zahl << " Invertiert: " << zahl_negiert_signed << std::endl;
Ob er gut geschrieben ist sei dahingestellt, aber er funktioniert ;-)

Jetzt dachte ich mir, ich fasse die Zeilen 2 und 3 zusammen und, was soll ich dsagen, es funktioniert nicht.
C++:
unsigned short zahl = 0;
unsigned short zahl2 = (~zahl) >> 1;
signed short zahl_negiert_signed = static_cast<signed short>(zahl2);
std::cout << "Zahl: " << zahl << " Invertiert: " << zahl_negiert_signed << std::endl;
Ich bekomme jetzt -1 als Ergebnis, statt 32767. Mit ein bißchen rumprobieren und dem Gebrauch anderer Zahlen, habe ich festegestellt, dass er im letzten Fall statt mit einer '0' mit einer '1' von links auffüllt, obwohl zahl als unsigned short deklariert wurde.

Meine Frage: Wieso wird in diesem Fall mit einer 1 aufgefüllt? Liegt es daran, dass ich die invertierte Zahl vorher nicht explizit als unsigned zwischenspeichere und somit davon ausgegangen wird, da das höchstwertigste Bit eine 1 ist, dass es sich um eine negative Zahl handelt und somit mit einer 1 aufgefüllt wird?

Viele Grüße
schiese
 

schiese

Erfahrenes Mitglied
#3
Wenn ich mir zahl2 ausgeben lasse erhalte ich -1. Das erwarte ich auch. Nur invertiere ich ja eine unsigned short und dachte, dass auch die invertierte Zahl, da der Ausgangsdatentyp vom Typ unsigned short ist, als solche interpretiert wird. Aber offensichtlich wird sie als signed short interpretiert, falls ich sie nicht explizit als unsigned short speicher oder einen Cast durchführe.
So funktioniert es:
C++:
unsigned short zahl2 = (unsigned short) ~zahl >> 1;
 
#4
Ich hab's mal in PHP mit Binärdarstellung gemacht; manchmal sagt ein Bild mehr als Worte.
Dass es jetzt 64 Bit sind ist egal, weil das eben der Wertebereich ist, das Prinzip ist aber dasselbe.
Ich denke, da könnte klar werden, was passiert.

binaer_001.png
 

schiese

Erfahrenes Mitglied
#6
Ja. Er ist int. In deinem Link ist das Beispiel auch drin. Unter 'Noncompliant Code Example'. An der interessanten Stelle steht dann allerdings: Whether or not value is negative is implementation-defined. Also wenn in einer Zeile den invertierten Ausdruck vorher casten. Lieber einmal mehr, dann ist man auf der sicheren Seite :-D

Die Vorgänge der Invertierung sind mir klar. Ich habe nur nicht verstanden, wieso die invertierte Zahl als negativ interpretiert wird.
 

schiese

Erfahrenes Mitglied
#7
Frage mal den Compiler (mittels auto und decltype), was der Typ von ~zahl2 ist.
Ich nehme an: int.
Ich habe hier noch mal eine Frage zu. Ich habe den Typ mit
C++:
typeid(zahl2).name()
bestimmt und nicht 'int' oder 'unsigned int', sondern 'i' erhalten. Die Ausgabe ist ja compilerabhängig.
Dann habe ich mir decltype und auto angeschaut und bin mir nicht sicher, wie ich mir den Typ ausgeben lassen kann. Ich habe es so gelesen, dass man eine neue Variable mit demselben (unbekannten) Typ einer anderen Variablen deklarieren kann.

Gruß
schiese
 

cwriter

Erfahrenes Mitglied
#8
bestimmt und nicht 'int' oder 'unsigned int', sondern 'i' erhalten. Die Ausgabe ist ja compilerabhängig.
Tönt eher nach einem Bug. Wie genau lässt du dir es ausgeben? Es scheint so, als würde einfach nur das erste Zeichen ausgegeben.


Dann habe ich mir decltype und auto angeschaut und bin mir nicht sicher, wie ich mir den Typ ausgeben lassen kann.
IntelliSense bzw. die IDE deines Vertrauens kann das oft.
Ich habe es so gelesen, dass man eine neue Variable mit demselben (unbekannten) Typ einer anderen Variablen deklarieren kann.
Genau; zumindest VS zeigt dann den "echten" Typ an.

Aber als direkter Lösungsvorschlag als alternative für typeid():
C++:
void showtype(int i) { std::cout << "int" << std::endl; }
void showtype(unsigned int i) { std::cout << "unsigned int" << std::endl; }
//... weitere typen
Gruss
cwriter
 

schiese

Erfahrenes Mitglied
#9
Ich lasse es mir wie folgt ausgeben
C++:
unsigned int zahlinvertiert = ~zahl;
std::cout << "Typ: " << typeid(zahlinvertiert).name();
Die Ausgabe ist: j
C++:
int zahlinvertiert = ~zahl;
std::cout << "Typ: " << typeid(zahlinvertiert).name();
Die Ausgabe ist: i

Das scheint eine Einstellung des GCC zu sein (siehe hier)
 

Neue Beiträge