C Code Schnippsel (HighByte LowByte Schiebereien) / Bit-wise Operator.

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • C Code Schnippsel (HighByte LowByte Schiebereien) / Bit-wise Operator.

    Hi. :)

    Da ich direkt mit Objective-C gestartet habe, und kein "Quereinsteiger" bin,
    hab ich etwas Probleme mit dem Verständnis hier.

    Es ist aus einem Ausschnitt aus einem Beispiel einer RS232 Übertragung.
    Ich denke es soll den zu übertragenen Wert in 4er Bit-Gruppen aufteilen um die Reihenfolge der Übertragung so zu sortieren, wie es das Empfangsgerät gern hätte (highByte/lowByte/blablabla ;)).

    Variablen sind alle ints.


    highByte = (Value >> 4);
    lowByte = (Value * 16) & 0xff;

    highByte0 = (highByte >> 4);
    highByte1 = (highByte & 0x0f);
    lowByte0 = (lowByte >> 4);
    lowByte1 = (lowByte & 0x0f);


    Ich spiel das mal durch wie es für mich aussieht:
    Benennen wir mal die 16 Bits der Variable "Value" von 0-F(Hex).
    F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0

    Zeile 1 belegt highByte mit
    "0|"0"|"0"|"0"|F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4

    Zeile 2 belegt lowByte mit
    B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |"0"|"0"|"0"|"0"
    &
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"1"|"1"|"1"|"1"|"1"|"1"|"1"|"1"
    =
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"| 3 | 2 | 1 | 0 |"0"|"0"|"0"|"0"

    Zeile 3 ist leer. :P

    Zeile 4 belegt highByte0 mit
    "0|"0"|"0"|"0"|"0|"0"|"0"|"0"|F | E | D | C | B | A | 9 | 8

    Zeile 5 belegt highByte1 mit
    "0|"0"|"0"|"0"|F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4
    &
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"1"|"1"|"1"|"1"
    =
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"| 7 | 6 | 5 | 4

    Zeile 6 belegt lowByte0 mit
    "0"|"0"|"0"|"0"| B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0

    Zeile 7 belegt lowByte1 mit
    B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |"0"|"0"|"0"|"0"
    &
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"1"|"1"|"1"|"1"
    =
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"

    Und spätestens nach der letzten Zeile wusste ich es stimmt etwas nicht. ;)
    Erwartet hätte ich, dass in jedem der 4 letzten Variablen 1/4 des Originalwerts zu finden ist.
    Also etwa so:
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0" | 3 | 2 | 1 | 0,
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"| 7 | 6 | 5 | 4,
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"| B | A |9 | 8,
    "0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"|"0"| F | E | D | C

    Ich schätze mal es liegt an meinem mangelnden Wissen und nicht an dem Code.

    Kann mich jemand erleuchten?
  • Also wen es sich bei den ersten beiden um 16 bit variablen handelt und diese nicht shiften sondern rotieren und bei den letzten vier um 8bit Variablen, dann würde tatsächlich ein einigermassen sinnvolles Ergebnis herauskommen. Dann sähe das ganze nämlich so aus:

    F E D C B A 9 8 7 6 5 4 3 2 1 0

    highbyte= 3 2 1 0 F E D C B A 9 8 7 6 5 4
    lowbyte = 0 0 0 0 0 0 0 0 3 2 1 0 F E D C

    h0 =B A 9 8
    h1 =7 6 5 4
    l0 =3 2 1 0
    l1 =F E D C

    es wäre also tatsächlich ein umsortieren in 4 vierer Pakete.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • So, nachdem ich mal wieder beim Absenden meines Beitrages geschmissen wurde, nur noch die Kurzfassung:

    Wenn man das auf die Verwendung von lowByta und loyByte1 kürzt, verstehe ich dich sehr gut. Kein Tippfehler?

    Du kannst aber die Nibbles (kleinere Einheiten werden ja nicht verwendet) mit 0x01, 0x02, 0x03 und 0x04 vorbelegen und mal schauen, was hinten ankommt.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Danke euch Beiden.

    Jetzt komm ich mir immerhin nicht mehr ganz so behämmert vor. ;)

    @Claus, guter Einfall der es wohl trifft.
    Die letzten Variablen sind nicht 8 bit, aber der Wert wird so formatiert am Ende, dass es passt ("%01x%01x", highByte0,highByte1).

    Stellt sich für mich nur die Frage: Woher weiß man ob einer Sprache/auf einem System bei ">>" geshiftet oder rotiert wird?
  • Wenn ich mich richtig erinnere, wird bei << immer mit Nullen aufgefüllt, bei >> wird das höchstwertige Bit wiederholt. Ich verlasse mich aber meistens nicht darauf, sondern maskiere das Ergebnis so, dass da immer das drin steht, was ich will.

    Wo hast Du bloß das Beispiel her? Es ist wirklich Quatsch - in LowByte1 kann zum Schluss nur eine 0 sein. Wenn man in Zeile 1 die 4 durch eine 8 ersetzt, in Zeile 2 das * 16 weglässt und die Ergenisse der Shifts ordentlich maskiert, müsste das rauskommen, was man erwartet.
    Multigrad - 360°-Produktfotografie für den Mac
  • Tobse001 schrieb:

    Danke euch Beiden.

    Jetzt komm ich mir immerhin nicht mehr ganz so behämmert vor. ;)

    @Claus, guter Einfall der es wohl trifft.
    Die letzten Variablen sind nicht 8 bit, aber der Wert wird so formatiert am Ende, dass es passt ("%01x%01x", highByte0,highByte1).

    Stellt sich für mich nur die Frage: Woher weiß man ob einer Sprache/auf einem System bei ">>" geshiftet oder rotiert wird?


    Also wie Mattik schon schreibt. Dafür gibt es keine Regeln. Diese ganz >> Geschichte stammt ja noch aus der Zeit wo die Compiler nicht optimieren und die prozessoren nicht multiplizieren konnten. Da wurde ein *4 zu einer Schleife mit 4x addieren. Dort konnte man mit diesem Shiften sehr gut optimieren.
    Dabei kannten manche Prozessoren den Befehl Shift, manche den Rotate und manche beides.

    Also so würde heute keiner mehr diesen Code schreiben.

    Wo hast Du den überhaupt her ?

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Doch, das ist weitestgehend definiert:

    a) Es wird nie rotiert. Wenn man rotieren will, muss man einen größeren Datentypen nehmen (nehmen wir mal an long) und dann zurechtschieben:

    Quellcode

    1. int16_t value = …
    2. int32_t overflow = ((int32_t)value) << 4;
    3. value |= (overflow >> 16);


    b) Beim Linksschieben wird stets mit 0 aufgefüllt.

    c) Beim Linksschieben von unsigned passiert sonst nichts, es sei denn, der Wert ist signed und tatsächlich negativ. Hier ist das Verhalten undefiniert.

    d) Beim Rechtsschieben wird mit 0 aufgefüllt, es sei denn, der Typ ist signed und hat tatsächlich einen negativen Wert. Nur in diesem Falle hängt es vom Compiler ab. (Ist also nicht undefiniert in dem Sinne, dass irgendwas passieren kann, sondern in dem Sinne, dass für jeden Compiler etwas anderes definiert sein kann.)

    So in etwa müsste das sein. Aber in der Tat hält man sich am liebsten aus derlei Kisten heraus. Ist einfach gesünder.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Thallius schrieb:

    Diese ganz >> Geschichte stammt ja noch aus der Zeit wo die Compiler nicht optimieren und die prozessoren nicht multiplizieren konnten.

    Quatsch. Wie schreibst Du 2^i? Bei mir ist das (1<<i). Willst Du pow() verwenden, und hoffen, dass das klappt? Wie willst du das n-te Bit extrahieren? Bei mir ist das (Value&(1<<n)). Willst Du da allen ernstes irgendwas mit pow() und Division konstruieren? Will ich drei Bytes kombieren, etwa R, G und B in ein int schreibe ich (R<<16|B<<8 |G). Das finde ich deutlich einfacher zu lesen als (R*65535+B*255+C). Aber ich find ja auch C++ besser als Obj-C, liegt also gewiss an mir :P
    C++
  • zerm schrieb:

    Thallius schrieb:

    Diese ganz >> Geschichte stammt ja noch aus der Zeit wo die Compiler nicht optimieren und die prozessoren nicht multiplizieren konnten.

    Quatsch. Wie schreibst Du 2^i? Bei mir ist das (1<<i). Willst Du pow() verwenden, und hoffen, dass das klappt? Wie willst du das n-te Bit extrahieren? Bei mir ist das (Value&(1<<n)). Willst Du da allen ernstes irgendwas mit pow() und Division konstruieren? Will ich drei Bytes kombieren, etwa R, G und B in ein int schreibe ich (R<<16|B<<8 |G). Das finde ich deutlich einfacher zu lesen als (R*65535+B*255+C). Aber ich find ja auch C++ besser als Obj-C, liegt also gewiss an mir :P


    Und in wiefern ist meine Aussage deswegen quatsch ?

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    Und in wiefern ist meine Aussage deswegen quatsch ?

    Sorry, ich hatte dich so verstanden, dass Du ausdrücken wolltest, dass die Shift-Operationen ein unnötiges Relikt aus alten Zeiten ist, die heute nicht mehr benötigt werden.

    Dass ein C-Compiler einem das mühsame Shift-Add bei Multiplikationen früher mal nicht abgenommen hat finde ich sehr interessant, habe ich noch nicht gehört. Hast Du da vielleicht noch mehr drüber? Mal schauen, ob ich irgendwo was dadrüber finde...Performance Guide von 1979 wäre echt mal spannend ;)
    C++