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:
unsigned char foo1: 3;
unsigned char foo2: 3;
unsigned char foo3: 3;
unsigned char foo4: 3;
unsigned char foo5: 3;
unsigned char foo6: 3;
unsigned char foo7: 3;
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 um char
campo próprio). Se todas as char
declarações tivessem sido substituídas por short
, haveria dois campos do tipo short
, 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 e unsigned 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:
unsigned short f1;
unsigned char f2;
union foo1 = f1:0.3;
union foo2 = f1:3.3;
union foo3 = f1:6.3;
union foo4 = f1:9.3;
union foo5 = f1:12.3;
union foo6 = f2:0.3;
union foo7 = f2:3.3;
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.