Integer zu 16Bit-Zahl konvertieren



  • Hallo Leute!

    Ich muss eine Zahl vom Typ int zu einer Zahl machen, die genau 16 Bits besitzt. Folgender Code von einem Freund tut das offenbar auch:

    unsigned int b = 500;
    unsigned char byte1 = b & 0x00FF;
    b >>= 8;
    unsigned char byte2 = b & 0x00FF;
    

    "byte2byte1" soll nun die gesuchte Darstellung ergeben. Ich verstehe allerdings nicht, was dieses "0x00FF" zu beudeten hat und was "b >>= 8" bewirkt. Könnt ihr mir helfen?

    Viele Grüße,
    wocknwolla



  • siehe "bitwise and" (+"bit mask") und "shift"



  • Und zu dem 0x00FF das ist eine Hexadezimale Zahl, 255 dezimal oder 0000 0000 1111 1111 in binär.



  • Vielen Dank erstmal. Trotzdem verschließt sich mir immer noch der Sinn der ganzen Sache... Ok, ich weiß jetzt, was das bitweise & macht und was mir die 0x00FF sagen will. Aber das erklärt mir irgendwie immer noch nicht, was die zweite und vierte Zeile des Codes genau machen.

    In der zweiten Zeile wird also die Hexadezimaldarstellung der Zahlen 500 und 255 "bitweise verglichen". Es ist wohl 500 = 0x01F4 und 255 = 0x00FF. Was folgt dann für byte1? Etwa byte1 = 0x00F0, also byte1 = 15*16 = 240? Nun wird um 8 Stellen nach rechts geshiftet, d.h. b = 0x0000. Nun wieder der bitweise Vergleich mit 255, also byte2 = 0x0000 = 0.

    Warum genau hat nun "byte2byte1" genau 16 Bits? byte1 kommt doch mit zwei Bits aus, byte2 sogar mit nur einem?! Ich checke es leider überhaupt nicht 😞



  • Ein Bit hat entweder den Zustand 0 oder 1. Vielleicht hilft dir das weiter



  • In der zweiten Zeile ist es

    0000 0001 1111 0100
    & 0000 0000 1111 1111
    ---------------------
      0000 0000 1111 0100
    

    In der dritten zeile wird dann geshiftet und dein b ist dann auf

    0000 0000 0000 0001
    

    und in der vierten zeile dann nochmal ein binäres &:

    0000 0000 0000 0001
    & 0000 0000 1111 1111
    ---------------------
      0000 0000 0000 0001
    

    Ergibt 244 für die erste Zahl und 1 für die zweite. Führende nullen vom int hab ich jetzt einfach mal weggelassen.



  • Dort wirds nichts verglichen, es ist eine Zuweisung! Die zweite Zeile macht ein bitweises UND mit dem Wert in Variable b und dem festen Wert 0x00FF. Wenn man sich 0x00FF in der binären Darstellung anguckt wie tkausl schon geschrieben hat sollte klar werden was die Zeile zu bedeuten hat. In der binären Darstellung sind nämlich genau die letzten 8 Bit gesetzt, daher werden in der Zeile nur die letzten 8 Bit von b nach byte1 kopiert. Dann wird b um 8 Bits nach rechts geschoben. Die ursprünglich letzten 8 Bit sind dann weg und es werden die nächsten 8 Bit nach byte2 kopiert. Als Übung empfehle ich dir mal zu überlegen wie man byte1 und byte2 wieder "zusammenbauen" kann, sodass du wieder den gleichen Wert wie in b erhälst (solange b maximal 16 Bit groß war).



  • DICKES DANKE! tkausls Darstellung und sebi707s erklärende Worte haben zusammen den Schalter bei mir umgelegt 🙂



  • Und warum der Umweg über zwei 8-Bit Zahlen?

    b &= 0xffff;
    


  • Warum nicht einfach casten?

    uint16_t b2 = (uint16_t)b;
    

  • Mod

    DarkShadow44 schrieb:

    Warum nicht einfach casten?

    uint16_t b2 = (uint16_t)b;
    

    Was passiert denn, wenn du den Cast weg lässt?



  • SeppJ schrieb:

    Was passiert denn, wenn du den Cast weg lässt?

    Dann muss man sich ne Standpauke vom Compiler von wegen "integer precision" anhören? Oder? 😃


  • Mod

    Finnegan schrieb:

    SeppJ schrieb:

    Was passiert denn, wenn du den Cast weg lässt?

    Dann muss man sich ne Standpauke vom Compiler von wegen "integer precision" anhören? Oder? 😃

    Das wäre an der Stelle eher ungewöhnlich. Kannst du einen Compiler nennen, der da warnt? Expliziter als so kann man kaum schreiben, dass man eine Konvertierung zu uint16_t wünscht.



  • SeppJ schrieb:

    Finnegan schrieb:

    SeppJ schrieb:

    Was passiert denn, wenn du den Cast weg lässt?

    Dann muss man sich ne Standpauke vom Compiler von wegen "integer precision" anhören? Oder? 😃

    Das wäre an der Stelle eher ungewöhnlich. Kannst du einen Compiler nennen, der da warnt? Expliziter als so kann man kaum schreiben, dass man eine Konvertierung zu uint16_t wünscht.

    Wenn man den cast wegläßt?
    Die Frage haste sicher überlesen. 😮



  • SeppJ schrieb:

    Finnegan schrieb:

    SeppJ schrieb:

    Was passiert denn, wenn du den Cast weg lässt?

    Dann muss man sich ne Standpauke vom Compiler von wegen "integer precision" anhören? Oder? 😃

    Das wäre an der Stelle eher ungewöhnlich. Kannst du einen Compiler nennen, der da warnt? Expliziter als so kann man kaum schreiben, dass man eine Konvertierung zu uint16_t wünscht.

    Nein, kann ich nicht. War mir nicht bewusst, dass die Zuweisung als so eindeutig gewollt durchgeht, daher auch das etwas unsichere "Oder?" :D.
    Ist mir bisher noch nicht aufgefallen, weil ich in meinem Code auch solche überflüssigen Casts immer hinschreibe - um im Code zu dokumentieren, dass es mit voller Absicht geschieht (immerhin könnten bei obigem Cast ein paar Bits flöten gehen).

    Finnegan



  • SeppJ schrieb:

    Finnegan schrieb:

    SeppJ schrieb:

    Was passiert denn, wenn du den Cast weg lässt?

    Dann muss man sich ne Standpauke vom Compiler von wegen "integer precision" anhören? Oder? 😃

    Das wäre an der Stelle eher ungewöhnlich. Kannst du einen Compiler nennen, der da warnt? Expliziter als so kann man kaum schreiben, dass man eine Konvertierung zu uint16_t wünscht.

    clang:

    foo.cpp:6:20: warning: implicit conversion loses integer precision: 'std::uint32_t' (aka 'unsigned int') to 'std::uint16_t' (aka 'unsigned short') [-Wconversion]
            std::uint16_t j = i;
                          ~   ^
    


  • VS auch ab Warning Level 4:

    warning C4244: 'initializing' : conversion from 'unsigned int' to 'uint16_t', possible loss of data
    

    Finde ich auch nicht verkehrt. Wenn man es so hinschreibt ist zwar ziemlich klar, dass es eine Konvertierung gibt aber wenn man Funktionen mit uint16_t als Parameter hat und dort einen int übergibt würde ich schon gerne eine Info kriegen.



  • DirkB schrieb:

    Und warum der Umweg über zwei 8-Bit Zahlen?

    b &= 0xffff;
    

    Welchen Datentyp muss b dann haben? unsigned int? Ich muss halt eine Zahl abspeichern, die genau 16 Bit hat. Und wenn ich diese nachher wieder auslese, sollen genau wieder 16 Bit gelesen werden. uint16_t funktioniert nicht, weil der Compiler dann irgendwie stresst.



  • uint16_t funktioniert nicht, weil der Compiler dann irgendwie stresst.

    Sehr genaue Aussage...

    #include <cstdint>
    


  • Hyde++ schrieb:

    uint16_t funktioniert nicht, weil der Compiler dann irgendwie stresst.

    Sehr genaue Aussage...

    #include <cstdint>
    

    Ja, sorry, ich schrieb den Beitrag, als ich nicht an einem der Uni-Rechner saß und deshalb die genaue Meldung nicht nachsehen konnte... cstdint habe ich eingebunden, aber genau da kommt dann eben die Meldung. Die lautet:

    error: #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options

    Da ich von Linux und Compilern und whatever nicht so viel Ahnung habe, weiß ich nicht, wo ich das hinschreiben müsste. Dies ist mein Makefile:

    CXX = g++
    CXXFLAGS = -O2 -Wall 
    
    ma5b: unit.o mapraview.o greyscale.o 
    	$(CXX) $(CXXFLAGS)  unit.o mapraview.o greyscale.o -o ma5b   
    
    greyscale.o: unit.h greyscale.h greyscale.cpp   
    	$(CXX) $(CXXFLAGS) -c greyscale.cpp 
    
    mapraview.o: unit.h greyscale.h greyscale.cpp mapraview.cpp 
    	$(CXX) $(CXXFLAGS) -c mapraview.cpp 
    
    .PHONY: clean 
    clean: 
    	rm greyscale.o mapraview.o
    

    Wo und wie würde ich jetzt diese Compiler Options hinzufügen müssen? Das Paket habe ich in die greyscale.cpp eingebunden.


Anmelden zum Antworten