Eu defini esta estrutura:
typedef struct
{
char A:3;
char B:3;
char C:3;
char D:3;
char E:3;
} col;
Eles sizeof(col)
me dão a saída de 3, mas não deveria ser 2? Se eu comentar apenas um elemento, o sizeof
é 2. Não entendo por quê: cinco elementos de 3 bits são iguais a 15 bits, e isso é menor que 2 bytes.
Existe um "tamanho interno" na definição de uma estrutura como esta? Só preciso de um esclarecimento, porque pela minha noção da linguagem até agora, esperava um tamanho de 2 bytes, não 3.
signed char
ouunsigned char
, você não pode dizer sem olhar a documentação se o compilador tratará 'simples'char
em um campo de bits como assinado ou não, e a decisão poderia (em teoria) ser diferente da decisão sobre se 'plain'char
é assinado ou não quando usado fora de um campo de bits._Bool
,signed int
,unsigned int
, ou algum outro tipo definido pela implementação.char
Portanto, usar se enquadra na categoria de 'outro tipo definido pela implementação'.Respostas:
Como você está usando
char
como tipo subjacente para seus campos, o compilador tenta agrupar bits por bytes e, como não pode colocar mais de oito bits em cada byte, ele pode armazenar apenas dois campos por byte.A soma total de bits que sua estrutura usa é 15, então o tamanho ideal para caber tantos dados seria a
short
.O código acima (para uma plataforma de 64 bits como a minha) realmente renderá
2
para a segunda estrutura. Para qualquer coisa maior que ashort
, a estrutura não preencherá mais de um elemento do tipo usado, portanto - para essa mesma plataforma - a estrutura terminará com o tamanho quatro paraint
, oito paralong
, etc.fonte
char
eshort
?char
sejam assinadas ...Porque você não pode ter um campo de pacote de bits que ultrapasse o limite mínimo de alinhamento (que é 1 byte), então eles provavelmente serão empacotados como
(as ordens de campo / preenchimento dentro do mesmo byte não são intencionais, é apenas para dar uma ideia, já que o compilador poderia defini-las como preferir)
fonte
Os primeiros dois campos de bits se encaixam em um único
char
. O terceiro não se encaixa nissochar
e precisa de um novo. 3 + 3 + 3 = 9 que não cabe em um caractere de 8 bits.Assim, o primeiro par recebe a
char
, o segundo par recebe achar
e o campo do último bit obtém um terceirochar
.fonte
A maioria dos compiladores permite que você controle o preenchimento, por exemplo
#pragma
, usando s . Aqui está um exemplo com GCC 4.8.1:Observe que o comportamento padrão do compilador existe por uma razão e provavelmente proporcionará melhor desempenho.
fonte
Embora o padrão ANSI C especifique muito pouco sobre como os campos de bits são compactados para oferecer qualquer vantagem significativa sobre "os compiladores têm permissão para compactar os campos de bits da maneira que acharem conveniente", ainda assim, em muitos casos, proíbe os compiladores de compactar as coisas da maneira mais eficiente.
Em particular, se uma estrutura contém campos de bits, um compilador é necessário para armazená-la como uma estrutura que contém um ou mais campos anônimos de algum tipo de armazenamento "normal" e então subdividir logicamente cada campo em suas partes de campo de bits constituintes. Assim, dado:
Se
unsigned char
fosse de 8 bits, o compilador seria obrigado a alocar quatro campos desse tipo e atribuir dois campos de bits a todos, exceto um (que estaria em umchar
campo próprio). Se todas aschar
declarações tivessem sido substituídas porshort
, haveria dois campos do tiposhort
, um dos quais conteria cinco campos de bits e o outro conteria os dois restantes.Em um processador sem restrições de alinhamento, os dados poderiam ser dispostos de forma mais eficiente usando
unsigned short
para os primeiros cinco campos eunsigned char
para os dois últimos, armazenando sete campos de três bits em três bytes. Embora deva ser possível armazenar oito campos de três bits em três bytes, um compilador só poderia permitir isso se existisse um tipo numérico de três bytes que pudesse ser usado como o tipo de "campo externo".Pessoalmente, considero os campos de bits definidos como basicamente inúteis. Se o código precisa trabalhar com dados compactados em binários, ele deve definir explicitamente os locais de armazenamento dos tipos reais e, em seguida, usar macros ou algum outro meio para acessar os bits deles. Seria útil se C suportasse uma sintaxe como:
Essa sintaxe, se permitida, tornaria possível para o código usar campos de bits de uma forma portátil, sem levar em conta os tamanhos das palavras ou ordenações de bytes (foo0 estaria nos três bits menos significativos de f1, mas aqueles poderiam ser armazenados no endereço inferior ou superior). Na ausência desse recurso, no entanto, as macros são provavelmente a única maneira portátil de operar com essas coisas.
fonte