Maski i przesunięcia bitowe – co to za czary?

Cześć!

Mam na imię Wojtek i jestem inżynierem od testowania Systemów Wbudowanych.

Właśnie trwa przedsprzeaż mojego kursu Wszystko o magistrali CAN – polecam!

Jeżeli kiedykolwiek czytając czyjś kod natknąłeś się na zapis typu:

syg3 = (frame & 0xFF000000) >> 24;

i sam widok Cię wzdragał, doskonale Cię rozumiem. Ten format jest trudny do ogarnięcia na pierwszy rzut oka. Ale jak tylko oswoisz się z powyższym zapisem, maski i przesunięcia okażą się nieocenionym przyjacielem w wielu sytuacjach.

Masek i przesunięć bitowych używamy wtedy, gdy chcemy z pewnej liczby (np. 0x12345678) wyciągnąć tylko jej część (np. 0x3456) i dalej posługiwać się tą skróconą formą.

Kiedy zastaniesz żonę w maseczce z zielonych ogórków, zachowaj śmiertelną powagę

Nazwa maski nie jest przypadkowo zbieżna z częścią garderoby zakrywającą twarz. Maska w odniesieniu do programowania również ma za zadanie zasłonić nam pewne rzeczy i skupić się jedynie na części istotnej dla nas.

Zanim omówimy maskę na konkretnym przykładzie, dwa słowa o konstrukcji ramek w automotive.

Ramki, czyli komunikaty wysyłane na magistrali są kontenerami zawierającymi w sobie zbiór zmiennych (inaczej: sygnałów) zapakowanych razem w jeden wagon. Załóżmy, że mam pewną ramkę składającą się z następujących sygnałów :

syg1 = 0xZZZZ
syg2 = 0xSSSS
syg3 = 0xPP
syg4 = 0xQQ
syg5 = 0xGGGG

Sygnały te są “zapakowane” w ramkę, która przychodzi do nas w formacie:

frame = 0xZZZZSSSSPPQQGGGG

Często w automotive używa się zapisu takich szesnastkowych ciągów bez “0x” na początku i dzieląc cyfry na pary znaków (czyli na bajty) dla większej czytelności.

Taka ramka może mieć więc zapis:

ZZ ZZ SS SS PP QQ GG GG

prawda, że czytelniejsze?

Zanim przejdziesz dalej: zakładam, że wiesz jak działa koniunkcja bitowa. Jeśli nie – rzuć okiem do wikipedi.

No dobrze, ale jesteśmy wybrednymi testerami. Nie potrzebujemy całej tej liczby, lecz chcemy tylko dobrać się do wartości syg3 (czyli miejsc PP), aby w swoim przypadku testowym porównać ją z wartością oczekiwaną.

Przeprowadzamy więc mnożenie bitowe:

   ZZ ZZ SS SS PP QQ GG GG
&  00 00 00 00 FF 00 00 00
_____________________________
=  00 00 00 00 PP 00 00 00 

Co tu się stało?

Na pozycjach, które nas interesowały postawiliśmy jedynki na każdym bicie (czyli 0xF szesnastkowo), na pozostałych zaś zera. W rezultacie po pomnożeniu dostaliśmy wartość: 

0xPP000000

ale to jeszcze nie nasza wartość syg3, ponieważ mamy zera z prawej strony, które zmieniają nam wartość liczby. Musimy więc dokonać jeszcze przesunięcia bitowego w prawą stronę, pamiętając że każdy znak szesnastkowy to 4 bity. Chcąc pozbyć się sześciu zer z prawej strony, przesuwamy liczbę o 4*6 = 24 bity

0xPP000000 >> 24 = 0xPP
// powyższa linijka to działanie matematyczne, znak = oznacza "równa się". Liczba po lewej stronie przesunięta o 24 bity jest równa liczbie po prawej stronie. Nie jest to fragment kodu.

mamy to!

wyłuskaliśmy samo 0xPP.

Skracając więc ten wywód, moglibyśmy zapisać od samego początku:

syg3 = (frame & 0xFF000000) >> 24;

Dla jasności przykładu, użyłem tu tylko eF-ów i zer. Możliwe jednak, że w layoucie ramki sygnał będzie zajmował np nie 8 a 7 bitów. Wtedy maska może wyglądać np. tak: 0x7F00.

Podsumowanie i linki

Temat operacji logicznych jest rozległy i celowo omówiłem tylko jego skrawek, metod, których najczęściej używałem przy testowaniu elektroniki samochodowej. Jeśli jednak chcesz poznać szerzej powyższe zagadnienia w ujęciu ogólnym, zachęcam Cię do zapoznania się z tą stroną:

https://binaryupdates.com/bitwise-operations-in-embedded-programming/

Zachęcam do pozostawienia komentarza pod wpisem, zwłaszcza w przypadku pytań lub niejasności.


Opublikowano

w

przez

Komentarze

3 odpowiedzi na „Maski i przesunięcia bitowe – co to za czary?”

  1. Awatar Slawomir
    Slawomir

    Cześć, mam pytanie w przykładzie: 0xPP000000 >> 24 = 0xPP
    mamy 6 zer/pozycji po prawej wiec chcemy się tego pozbyć i przesunąć w prawo czyli te 6×4=24. -> OK
    A w przykładzie: syg3 = (frame & 0xFF0000) >> 24; mamy 4 pozycje po prawej których chcielibyśmy się pozbyć to czemu nie użyć przesunięcia 4×4 czyli >> 16?
    Pytanie czym się lewa strona wypełni po większym przesunięciu?

    1. Awatar admin

      Dzięki za kolejne wyłapanie błędu, powinieneś zostać moim korektorem 😉 zjadłem tam dwa zera, już jest poprawione.
      Z wypełnieniem trafna uwaga, choć w większości przypadków przy przesunięciach brakujące pozycje wypełniają się zerami.

      1. Awatar Slawomir
        Slawomir

        Nie ma problemu 🙂 Tak raczej by wypełniło zerami ale wiadomo lepiej uważać.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *