Domanda

Per chiarire la mia domanda, Partiamo subito con un programma di esempio:

#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));
}

L'uscita è "8", nel senso che i 56 bit (7 byte) voglio confezionare vengono confezionate in 8 byte, apparentemente sprecare un intero byte. Curioso di come il compilatore stava ponendo questi bit in memoria, ho provato scrivendo valori specifici &c, per esempio:.

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);
}

Come era prevedibile, il x86_64 utilizzando Visual Studio 2010, accade quanto segue:

*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

ecc.

Dimenticate portabilità per un attimo e assume vi preoccupate per una CPU, un compilatore e un ambiente di runtime. Perché non è possibile VC ++ confezionare questa struttura in 7 byte? È una cosa di parola di lunghezza? Il MSDN docs su #pragma pack dice " l'allineamento di un membro sarà su un confine che è o un multiplo di n [1 nel mio caso] o un multiplo della dimensione degli Stati, a seconda di quale è più piccolo." Qualcuno mi può dare qualche idea del motivo per cui ho un sizeof 8 e non 7?

È stato utile?

Soluzione

MSVC ++ alloca sempre almeno un'unità di memoria che corrisponde al tipo utilizzato per il campo di bit. Hai usato unsigned int, il che significa che un unsigned int viene allocata inizialmente, e un altro unsigned int viene allocata quando il primo è esaurito. Non c'è alcun modo per imporre MSVC ++ per tagliare la parte non utilizzata del secondo unsigned int.

In sostanza, MSVC ++ interpreta il vostro unsigned int come un modo per esprimere la requisiti di allineamento per l'intera struttura.

tipi Usa più piccole per i tuoi bit-field (unsigned short e unsigned char) e raggruppare i bit-campi in modo da riempire l'unità assegnata interamente -. In questo modo si dovrebbe essere in grado di mettere in valigia le cose più strettamente possibile

Altri suggerimenti

a bit vengono memorizzati nel tipo che si definisce. Dal momento che si sta utilizzando unsigned int, e non si adatta in un unico unsigned int poi il compilatore deve utilizzare un secondo intero e memorizzare gli ultimi 24 bit in quell'ultimo intero.

Bene si utilizza unsigned int che risulta essere a 32 bit in questo caso. Il confine successiva (per adattarsi al campo di bit) per unsigned int è di 64 bit => 8 byte.

PST è giusto. Il membri sono allineati su limiti di 1 byte, (o più piccoli, dal momento che si tratta di un campo di bit). La struttura complessiva ha dimensioni 8, ed è allineato su un confine di 8 byte. Questo è conforme sia l'opzione pack lo standard e. La documentazione non dicono che non ci sarà alcuna imbottitura alla fine.

Per fare un altro interessante illustra quello che sta succedendo, si consideri il caso in cui si desidera mettere in valigia una struttura che attraversa un tipo di confine. Per es.

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

Questa struttura non può essere confezionato in 6 byte che utilizzano MSVC per quanto ne so. Tuttavia, siamo in grado di ottenere l'effetto desiderato di imballaggio rompendo i primi due campi:

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; 
};

Questo può effettivamente essere confezionato in 6 byte. Tuttavia, l'accesso al campo di costo originale è estremamente scomodo e brutto. Un metodo è quello di lanciare un puntatore state_packed ad una struttura specializzata manichino:

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;

Se qualcuno conosce un modo più elegante di fare questo, mi piacerebbe sapere!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top