2010-12-28 23 views
11

Piszę aplikację C++ dla Windows XP/Vista/7 przy użyciu Visual Studio 2008. Niektóre z moich struktur używają pola bitowego, jak pokazano w przykładzie.Który koniec pola bitowego jest najbardziej znaczącym bitem?

typedef struct myStruct_tag 
{ 
    BYTE myVar1; 
    WORD myVar2; 
    WORD myVar3; 
    union 
    { 
     struct 
     { 
      BYTE   :1; 
      BYTE field1 :1; 
      BYTE field2 :1; 
      BYTE reserved :5; 
     } myBitField; 
     BYTE myVar4; 
    }; 
    BYTE myVar5; 
    BYTE myVar6; 
} myStruct_t; 

Który koniec pola jest najbardziej znaczącym bitem?

+2

Uwaga: Zgodnie z normą, MSB nie jest zdefiniowany. Na twojej platformie podejrzewam, że 'zastrzeżone' zawiera MSB, ale nie jestem pozytywny. –

+0

@Billy: To wygląda na odpowiedź. –

+0

Er ... To dość dziwne pytanie. W deklaracji znajdują się tylko 3-bitowe pola. 2 z nich to 1-bitowe pola bitowe, tzn. Nie ma problemu z "tym końcem", ponieważ istnieje tylko 1 bit. Jedyne wielobitowe pole bitowe o nazwie 'zarezerwowane', które sugeruje, że nie jest w ogóle używane. Zasadniczo jedynym polem bitowym, o które pytasz można się ubiegać, jest 'zarezerwowane'. Pytasz konkretnie o "zarezerwowane"? Jeśli nie, wyjaśnij swoje pytanie. – AnT

Odpowiedz

18

C99 standardowy 6.7.2.1/10 (Kopalnia nacisk):

implementacja może przeznaczyć dowolną adresowalny moduł pamięci na tyle duże, aby trzymać bitfield. Jeśli pozostanie wystarczająca ilość miejsca, pole bitowe, które następuje bezpośrednio po innym polu bitowym w strukturze, zostanie zapakowane w sąsiednie bity tego samego urządzenia. Jeśli pozostanie niewystarczająca ilość miejsca, to, czy pole bitowe, które nie pasuje, zostanie umieszczone w następnej jednostce lub zachodzi na sąsiednie jednostki, jest definiowane przez implementację. Kolejność przydzielania pól bitowych w jednostce (od wysokiego do niskiego lub niskiego rzędu po wysoki) jest zdefiniowana w ramach implementacji. Wyrównanie adresowalnej jednostki pamięci jest nieokreślone.

Zamówienie musi być udokumentowane przez implementację kompilatora.

Jednak wiele informacji na temat implementacji bitfieldów to implementacja zdefiniowana lub nieokreślona, ​​że ​​używanie ich do modelowania sprzętu, protokołu przewodowego lub pól bitowych formatu pliku w przenośny sposób nie jest warte wysiłku.

Jeśli chcesz, aby „bitowe pola” modelować coś zewnętrznego programu (jak wyżej rzeczy), użyj wyraźne maski, ustawiania i usuwania bitów przy użyciu standardowych operatorów bitową (|, '& , ~ , < < `itp.). Użyj funkcji pomocniczych w linii pomocniczej (lub nawet makr, jeśli musisz), aby ułatwić to zrozumienie kodu.

+2

+10 gdybym mógł. Twoja odpowiedź na to pytanie jest najlepszym powodem, aby nie używać bitfieldów do głównych rzeczy, które według ludzi są przydatne. –

+0

Nie zdawałem sobie sprawy, że ludzie próbują używać ich w przenośny sposób. Jedyne, co widziałem, to "rozmawiać ze sprzętem z mojego programu, który używa kompilatora X". I spójrz na wszystkie ziliony z "Robię to w kompilatorze X, jak to zrobić w pytaniach kompilatora Y". –

+0

@CodeArominator: jako przykład widziałem pola bitowe używane do łamania komunikatów protokołu sieciowego lub formatów plików binarnych. Zauważyłem także, że niektóre z tych kodów nie działają podczas kompilacji dla innej platformy. –

2

Jeśli pytasz o to, które bity w myBitField są przechowywane, w których bitach bajtu w pamięci, jest to wyraźnie niezdefiniowane przez standardy C. Będziesz musiał uczyć się poprzez eksperymenty. Prawdopodobnie warto, jeśli robisz coś tam, gdzie ma to znaczenie, zamiast tego użyj metody, w której #define field1 jako wartości szesnastkowej (na przykład 0x40 lub 0x02) i umieść ją tam, gdzie chcesz.

+0

Niestety, testowanie funkcjonalne tego fragmentu kodu trwa co najmniej tygodnie, a nawet miesiące. (Jest wiele rzeczy, które trzeba napisać, aby naprawdę przetestować którykolwiek z nich, ponieważ jestem w punkcie, w którym wszystko, co zostało do napisania, jest mniej lub bardziej współzależne od wszystkiego innego.) Zdefiniowane stałe są opcją, ale wolałbym używać pól bitowych, ponieważ ten pierwszy wymagałby * więcej * więcej logiki w moim kodzie. –

+1

Cóż, szybki eksperyment powinien pokazać, co robi teraz kompilator ... wystarczy zdefiniować związek jak powyżej, przypisać 0 do 'myVar4', a następnie przypisać 1 do' field1' i wydrukować wynikową wartość z 'myVar4'. Chciałbym zawiesić nazwę na nieużywanym bicie zdefiniowanym przed 'field1', jednak, aby kompilator nie zoptymalizował go. – jmaynard

4

Visual Studio 2008 kompilatora docs wskazują:

Kolejność danych deklarowanych jako pól bitowych jest od niskiego do wysokiego bit

Od "C++ Bit Fields", MSDN C++ Language Reference, Visual Studio 2008 version

+0

Jak zauważyli inni, odpowiednie normy nie określają tego i dobrze jest napisać kod zgodny ze standardami, ale jest to odpowiedź na zadane pytanie, a czytelnik może zdecydować, czy chce na dobre wykorzystać swoje uprawnienia. lub za super. ; P – rakslice

Powiązane problemy