Frage

meine Frage zu klären, wollen sie mit einem Beispiel-Programm starten:

#include <stdio.h>

#pragma pack(push,1)
struct cc {
    unsigned int a   :  3;  
    unsigned int b   : 16;
    unsigned int c   :  1;
    unsigned int d   :  1;
    unsigned int e   :  1;
    unsigned int f   :  1;
    unsigned int g   :  1;
    unsigned int h   :  1;
    unsigned int i   :  6;  
    unsigned int j   :  6;  
    unsigned int k   :  4;  
    unsigned int l   : 15;
};
#pragma pack(pop)

struct cc c;

int main(int argc, char **argv)

{   printf("%d\n",sizeof(c));
}

Der Ausgang „8“ ist, was bedeutet, dass die 56 Bits (7 Byte) Ich packte verpacken möchten in 8 Bytes werden, scheinbar ein ganzes Byte zu verschwenden. Neugierig, wie die Compiler diese Bits aus im Speicher lag, habe ich versucht, bestimmte Werte zu &c schreiben, z.

int main (int argc, char ** argv)

{
unsigned long long int* pint = &c;
*pint = 0xFFFFFFFF;
printf("c.a = %d", c.a);
...
printf("c.l = %d", c.l);
}

Wie vorherzusehen war, auf x86_64 mit Visual Studio 2010, geschieht Folgendes:

*pint = 0x00000000 000000FF :

c[0].a = 7
c[0].b = 1
c[0].c = 1
c[0].d = 1
c[0].e = 1
c[0].f = 1
c[0].g = 0
c[0].h = 0
c[0].i = 0
c[0].j = 0
c[0].k = 0
c[0].l = 0

*pint = 0x00000000 0000FF00 :

c[0].a = 0
c[0].b = 0
c[0].c = 0
c[0].d = 0
c[0].e = 0
c[0].f = 0
c[0].g = 1
c[0].h = 127
c[0].i = 0
c[0].j = 0
c[0].k = 0
c[0].l = 0


*pint = 0x00000000 00FF0000 :

c[0].a = 0
c[0].b = 0
c[0].c = 0
c[0].d = 0
c[0].e = 0
c[0].f = 0
c[0].g = 0
c[0].h = 32640
c[0].i = 0
c[0].j = 0
c[0].k = 0
c[0].l = 0

etc.

Vergessen Portabilität für einen Moment und nehmen Sie eine CPU kümmern, einen Compiler und eine Laufzeitumgebung. Warum kann nicht VC ++ diese Struktur in 7 Byte einpacken? Ist es eine Wortlänge Sache? Die MSDN-Dokumentation auf #pragma pack sagt " die Ausrichtung eines Elements wird an einer Grenze sein, die entweder ein Vielfaches von n [1 in meinem Fall] oder ein Vielfaches der Größe des Bauteils ist, je nachdem, was kleiner ist.“ Kann mir jemand eine Vorstellung davon, warum ich ein sizeof 8 und 7 nicht bekommen?

War es hilfreich?

Lösung

MSVC ++ weist immer mindestens eine Einheit des Speichers, entspricht dem Typ, den Sie für Ihre Bit-Feld verwendet. Sie verwendet unsigned int, was bedeutet, dass ein unsigned int ursprünglich zugeordnet ist, und eine andere unsigned int zugeordnet wird, wenn der erste erschöpft ist. Es gibt keine Möglichkeit MSVC ++ zu zwingen, den ungenutzten Teil des zweiten unsigned int zu trimmen.

Im Grunde MSVC ++ interpretiert Ihre unsigned int als eine Möglichkeit, die Ausrichtungsanforderungen für die gesamte Struktur zum Ausdruck bringen.

Verwenden kleinere Typen für Ihre Bit-Felder (unsigned short und unsigned char) und neu zu gruppieren, die die Bit-Felder, so dass sie die zugewiesene Einheit vollständig ausfüllen -. Sie können sollen möglichst eng die Lage sein, Sachen zu packen

Andere Tipps

Bitfelder sind in der Art gespeichert, dass Sie definieren. Da Sie unsigned int verwenden, und es wird in einem einzigen unsigned int dann muss der Compiler eine zweite ganze Zahl verwenden und speichert die letzten 24 Bits in der letzten ganzen Zahl nicht passen.

Nun, Sie unsigned int verwenden, das geschieht 32 Bit in diesem Fall zu sein. Die nächste Grenze (zu passen, das Bitfeld) für unsigned int ist 64 Bit => 8 Bytes.

pst ist richtig. Die Mitglieder ausgerichtet sind, auf 1-Byte-Grenzen (oder kleiner, da es sich um ein Bitfeld ist). Die Gesamtstruktur hat Größe 8 und wird auf einer 8-Byte-Grenze ausgerichtet ist. Dies entspricht sowohl den Standard und die pack Option. Die docs sagen nie wird es am Ende keine Polsterung sein.

geben, eine weitere interessante zeigt, was los ist, betrachten wir den Fall, wo Sie eine Struktur packen wollen, die einen Typ-Grenze überschreitet. Z.

struct state {
    unsigned int cost     : 24; 
    unsigned int back     : 21; 
    unsigned int a        :  1; 
    unsigned int b        :  1; 
    unsigned int c        :  1;
};

Diese Struktur kann nicht in 6 Bytes gepackt werden MSVC verwenden, soweit ich weiß. Wir können aber den gewünschten Packungseffekt durch Aufbrechen der ersten beiden Felder erhalten:

struct state_packed {
    unsigned short cost_1   : 16; 
    unsigned char  cost_2   :  8;
    unsigned short back_1   : 16; 
    unsigned char  back_2   :  5;
    unsigned char  a        :  1; 
    unsigned char  b        :  1; 
    unsigned char  c        :  1; 
};

Dies kann in der Tat in 6 Bytes gepackt werden. Um jedoch das ursprüngliche Kostenfeldes Zugriff ist extrem umständlich und hässlich. Ein Verfahren ist ein state_packed Zeiger auf eine spezialisierte Dummy-Struktur zu werfen:

struct state_cost {
    unsigned int cost     : 24;
    unsigned int junk     :  8; 
};

state_packed    sc;
state_packed *p_sc = &sc;

sc.a = 1;
(*(struct state_cost *)p_sc).cost = 12345;
sc.b = 1;

Wenn jemand eine elegantere Art und Weise, dies zu tun weiß, ich würde gerne wissen!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top