Bitmanipulationen mit signed Datentypen (Java)

Wenn der speicherplatzbewusste Cpp-Programmierer seine ersten Schritte in die Welt von Java wagt hört man immer wieder die Frage nach den unsigned Datentypen. Anfangs dürfte das Fehlen dieser eine gewisse Umstellung kosten, jedoch nicht weiter schlimm sein. Etwas schwieriger wird der Umgang jedoch mit den Bitmanipulationen solcher unsigned Datentypen wenn beispielsweise hardwarenah programmiert werden muss.


Das größte Problem ist hierbei die Umwandlung der Datentypen durch einen Cast. Zur Verdeutlichung ein kleines Beispiel:

(short)35:                      0000 0000 0010 0011
(int)35:    0000 0000 0000 0000 0000 0000 0010 0011

(short)-35:                     1111 1111 1101 1101
(int)-35:   1111 1111 1111 1111 1111 1111 1101 1101


Wenn ein positiver Wert gecastet wird, werden die neuen Stellen mit Nullen gefüllt. Bei einem negativen Wert werden sie mit Einsen gefüllt. Dieser Sachverhalt ist für den Nachfolgenden Code von Bedeutung.

#include "iostream"

int main()
{
  short s1 = -24576;
  s1 = s1 << 1;
  int g1 = s1;

  short s2 = -24576;
 int g2 = s2 << 1;

  std::cout << "g1:" << g1 << " g2:" << g2 << std::endl;
  std::cin.sync();
  std::cin.get();

  return 0;
} // Output(MS C++) g1:16384 g2:-49152

Das Ergebnis ist zunächst einmal verblüffend. Sowohl für g1 als auch für g2 werden die gleichen Operationen ausgeführt. Das Ergebnis ist jedoch verschieden. Der Grund liegt darin, dass für g1 zuerst geshiftet und dann gecastet wird. Bei g2 wird zuerst gecastet und dann geshiftet. Das ganze kann man dem Code nicht ansehen. Beide Ergebnisse sind übrigens falsch.

Lösung 1:
                    1010 0000 0000 0000
                    0100 0000 0000 0000 shift
0000 0000 0000 0000 0100 0000 0000 0000 cast

Lösung 2:
                    1010 0000 0000 0000
1111 1111 1111 1111 1010 0000 0000 0000 cast
1111 1111 1111 1111 0100 0000 0000 0000 shift


Um dem Problem zu entgehen könnte man sich die Casts bis zum Schluss aufheben oder überhaupt nicht casten. Das ganze funktioniert in Java leider nicht. Bei jeder Bitmanipulation erhält man in Java einen Integer zurück. Leider benötigt man oft kleinere Datentypen wie short oder byte um beispielsweise eine Checksumme zu berechnen. In Java muss man deshalb die störenden Einsen  maskieren.

public class main
{
  public static void main(String[] args)
  {
  
    short s1 = -24576;
    int g1 = (0xffff & s1) << 1;
  
    System.out.println(g1);
  }
}
Nun stimmt auch die Lösung von 81920.

Lösung 3:
                    1010 0000 0000 0000

1111 1111 1111 1111 1010 0000 0000 0000 cast
0000 0000 0000 0000 1010 0000 0000 0000 mask
0000 0000 0000 0001 0100 0000 0000 0000 shift



Bookmark and Share

0 Kommentare:

Kommentar veröffentlichen