C Campos de Bits
Muitas informações de um programa são pequenas: "o despertador está ligado?" (sim ou não), "que dia da semana?" (1 a 7), "que hora?" (0 a 23). Guardar cada uma num unsigned inteiro, que tem 32 bits, é como usar uma mala grande para levar um par de meias. Os campos de bits (bit-fields) deixam você dizer ao C quantos bits cada membro de uma struct precisa, e ele encaixa vários membros no mesmo espaço.
- A sintaxe
unsigned ativo : 1;e o que o número depois dos dois-pontos quer dizer. - Quantos valores cabem em 1, 2, 3… bits, e como escolher a largura.
- Quanto espaço se economiza, medido com
sizeof. - O que acontece quando você guarda um valor que não cabe (e o aviso do compilador).
- A pegadinha do
int x : 1, que guarda-1em vez de1. - Os limites: não dá para pegar o endereço de um campo (adeus,
scanfdireto), nem usarsizeofnele, e a ordem dos bits na memória depende do compilador.
Esta aula usa structs (veja Structs) e fala de bits, os zeros e uns que formam cada número (a aula Memória, Bits e Bytes explica). Todos os programas foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa.
A ideia: uma gaveta com divisórias
Imagine uma gaveta de cozinha. Você pode jogar tudo lá dentro, ou pôr divisórias: um espaço estreito para os palitos, um médio para as colheres, um largo para as conchas. A gaveta é a mesma; as divisórias só aproveitam melhor o espaço.
Um unsigned é a gaveta: tem 32 bits. Um campo de bits é uma divisória: você diz "este membro usa 1 bit, este usa 5, este usa 6", e o compilador coloca todos, lado a lado, dentro da mesma gaveta de 32 bits.
| Informação do despertador | Valores possíveis | Bits que bastam |
|---|---|---|
| Está ligado? | 0 ou 1 | 1 bit |
| Hora | 0 a 23 | 5 bits (cabem 0 a 31) |
| Minuto | 0 a 59 | 6 bits (cabem 0 a 63) |
| Dia da semana | 1 a 7 | 3 bits (cabem 0 a 7) |
| Total | 15 bits: cabe numa gaveta só | |
1. O problema: uma struct "folgada"
Primeiro, o despertador da Ana do jeito que você já sabe fazer, um unsigned para cada informação:
#include <stdio.h>
struct Despertador {
unsigned ativo;
unsigned hora;
unsigned minuto;
unsigned dia;
};
int main(void) {
struct Despertador d = {1, 6, 30, 2};
printf("Toca às %02u:%02u no dia %u (ativo: %u)\n", d.hora, d.minuto, d.dia, d.ativo);
printf("sizeof: %zu bytes\n", sizeof d);
return 0;
}
$ gcc -std=c23 -Wall -Wextra semcampos.c -o semcampos $ ./semcampos Toca às 06:30 no dia 2 (ativo: 1) sizeof: 16 bytes
Quatro membros de 4 bytes cada: 16 bytes, ou 128 bits, para guardar 15 bits de informação. O %02u mostra o número sem sinal com dois dígitos, completando com zero à esquerda (veja Formatos do printf); o sizeof mede o tamanho em bytes (aula sizeof).
2. A sintaxe: dois-pontos e a largura
Agora o mesmo despertador com campos de bits. A única mudança está dentro da struct:
#include <stdio.h>
struct Despertador {
unsigned ativo : 1;
unsigned hora : 5;
unsigned minuto : 6;
unsigned dia : 3;
};
int main(void) {
struct Despertador d = {1, 6, 30, 2};
printf("Toca às %02u:%02u no dia %u (ativo: %u)\n", d.hora, d.minuto, d.dia, d.ativo);
printf("sizeof: %zu bytes\n", sizeof d);
d.hora = 23;
d.minuto = 59;
d.ativo = 0;
printf("Agora: %02u:%02u (ativo: %u)\n", d.hora, d.minuto, d.ativo);
return 0;
}
- unsigned
- O tipo do campo: inteiro sem sinal (só zero e positivos). É o tipo mais usado em campos de bits, e a seção 5 mostra por quê.
- ativo
- O nome do membro, como em qualquer
struct. - : 1
- A largura do campo, em bits. Leia "
ativoocupa 1 bit". Os espaços em volta dos dois-pontos são opcionais; aqui eles só alinham a coluna. - hora : 5
- 5 bits guardam de 0 a 31: sobra espaço para 0 a 23.
- d.hora = 23;
- Fora da
struct, nada muda: você lê e escreve o campo com o ponto, como um membro comum. - {1, 6, 30, 2}
- A inicialização também é igual: os valores vão na ordem dos membros.
$ gcc -std=c23 -Wall -Wextra campos.c -o campos $ ./campos Toca às 06:30 no dia 2 (ativo: 1) sizeof: 4 bytes « eram 16 Agora: 23:59 (ativo: 0)
Mesmo comportamento, um quarto do espaço. Os quatro campos somam 15 bits e couberam numa única "gaveta" de 4 bytes (32 bits); os 17 bits que sobram ficam sem uso.
Experimente: rode e veja o sizeof. Depois acrescente um campo unsigned segundo : 6;: o tamanho muda? (São 21 bits: ainda cabe em 32.) Agora acrescente unsigned ano : 12; (33 bits no total) e veja o que acontece com o sizeof.
#include <stdio.h>
struct Despertador {
unsigned ativo : 1;
unsigned hora : 5;
unsigned minuto : 6;
unsigned dia : 3;
};
int main(void) {
struct Despertador d = {1, 6, 30, 2};
printf("Toca às %02u:%02u no dia %u (ativo: %u)\n", d.hora, d.minuto, d.dia, d.ativo);
printf("sizeof: %zu bytes\n", sizeof d);
return 0;
}
Quando os bits passam de 32, o compilador abre uma segunda gaveta e o sizeof pula para 8. O tamanho cresce de 4 em 4 bytes, porque cada "gaveta" é um unsigned inteiro.
3. Quanto cabe em cada largura
Cada bit a mais dobra a quantidade de valores. Com n bits sem sinal, cabem os números de 0 até 2n − 1:
| Largura | Valores (unsigned) | Serve para… |
|---|---|---|
: 1 | 0 a 1 | sim/não, ligado/desligado |
: 2 | 0 a 3 | 4 opções (P, M, G, GG) |
: 3 | 0 a 7 | dia da semana |
: 4 | 0 a 15 | mês (1 a 12) |
: 5 | 0 a 31 | dia do mês, hora |
: 6 | 0 a 63 | minuto, segundo |
: 8 | 0 a 255 | um byte inteiro (uma cor RGB) |
: 12 | 0 a 4095 | ano |
A regra para escolher: ache o maior valor que o campo vai guardar e pegue a menor largura em que ele cabe. Para o mês (até 12): 3 bits vão até 7 (não dá); 4 bits vão até 15 (dá).
4. Quando o valor não cabe
O campo nivel abaixo tem 3 bits (0 a 7). O que acontece se a Ana tentar guardar 9?
#include <stdio.h>
struct Volume {
unsigned nivel : 3;
};
int main(void) {
struct Volume v = {0};
v.nivel = 7;
printf("nível 7 -> %u\n", v.nivel);
v.nivel = 9;
printf("nível 9 -> %u\n", v.nivel);
return 0;
}
$ gcc -std=c23 -Wall -Wextra estouro.c -o estouro
estouro.c: In function ‘main’:
estouro.c:11:15: warning: unsigned conversion from ‘int’ to ‘unsigned char:3’ changes value from ‘9’ to ‘1’ [-Woverflow]
11 | v.nivel = 9;
| ^
$ ./estouro
nível 7 -> 7
nível 9 -> 1 « o 9 virou 1
- unsigned conversion from ‘int’ to ‘unsigned char:3’
- "Conversão sem sinal de
intpara um campo de 3 bits". O gcc descreve o campo comounsigned char:3: o tipo pequeno que ele usou por dentro e a largura. - changes value from ‘9’ to ‘1’
- "Muda o valor de 9 para 1". O compilador já fez a conta e avisa o resultado.
- [-Woverflow]
- A regra do aviso: overflow é "transbordar". Ela vem ligada mesmo sem
-Wall.
Por que 1? Em binário, 9 é 1001. O campo só tem lugar para os 3 bits da direita (001); o bit que sobra à esquerda é jogado fora. É como um hodômetro de carro com 3 dígitos: depois de 999 ele volta para 000. Em conta: o valor guardado é o resto da divisão por 8 (9 % 8 = 1).
O Clang, compilador do editor, avisa com outras palavras: implicit truncation from 'int' to bit-field changes value from 9 to 1 [-Wbitfield-constant-conversion] ("truncamento implícito", isto é, corte escondido).
Com uma variável, nenhum aviso
O compilador só avisa quando o número está escrito direto no código. Se o valor vem de uma variável, o corte acontece em silêncio:
#include <stdio.h>
struct Volume {
unsigned nivel : 3;
};
int main(void) {
struct Volume v = {0};
for (unsigned i = 5; i <= 10; i++) {
v.nivel = i;
printf("guardei %2u, ficou %u\n", i, v.nivel);
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra estouro2.c -o estouro2 « nenhum aviso $ ./estouro2 guardei 5, ficou 5 guardei 6, ficou 6 guardei 7, ficou 7 guardei 8, ficou 0 « deu a volta guardei 9, ficou 1 guardei 10, ficou 2
Para campos unsigned, esse "dar a volta" é garantido pela linguagem: não é erro, é aritmética de relógio. Mas quase nunca é o que você queria. Por isso, confira o valor antes de guardar num campo pequeno (if (i <= 7)) ou dê ao campo a largura certa.
Missão: o volume da caixinha de som da Ana agora vai até 10, mas o campo nivel só guarda até 7. Mude só a largura do campo para que a última linha mostre guardei 10, ficou 10.
#include <stdio.h>
struct Volume {
unsigned nivel : 3;
};
int main(void) {
struct Volume v = {0};
for (unsigned i = 5; i <= 10; i++) {
v.nivel = i;
printf("guardei %2u, ficou %u\n", i, v.nivel);
}
return 0;
}
#include <stdio.h>
struct Volume {
unsigned nivel : 4;
};
int main(void) {
struct Volume v = {0};
for (unsigned i = 5; i <= 10; i++) {
v.nivel = i;
printf("guardei %2u, ficou %u\n", i, v.nivel);
}
return 0;
}
5. A pegadinha do int x : 1
E se o campo for int (com sinal) em vez de unsigned? Com sinal, um dos bits serve para dizer se o número é negativo. Num campo de 1 bit, esse bit é o único que existe:
#include <stdio.h>
struct Flags {
int ligado : 1;
bool aceso : 1;
};
int main(void) {
struct Flags f = {0};
f.ligado = 1;
f.aceso = 1;
printf("ligado = %d\n", f.ligado);
printf("aceso = %d\n", f.aceso);
if (f.ligado == 1) printf("ligado é 1\n");
else printf("ligado NÃO é 1\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra sinal.c -o sinal
sinal.c: In function ‘main’:
sinal.c:14:18: warning: comparison is always false due to limited range of data type [-Wtype-limits]
14 | if (f.ligado == 1) printf("ligado é 1\n");
| ^~
$ ./sinal
ligado = -1 « guardei 1, saiu -1
aceso = 1
ligado NÃO é 1
- Um campo
intde 1 bit só guarda dois valores: 0 e −1. O 1 não existe nele. - O gcc percebeu na comparação: comparison is always false due to limited range of data type = "a comparação é sempre falsa por causa do alcance limitado do tipo".
- O Clang (editor) avisa já na atribuição:
implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1. - O campo
bool aceso : 1funciona como esperado: guarda 0 ou 1. Em C23,boolé palavra-chave C23; no C99 a C17, escreva#include <stdbool.h>(veja bool).
unsigned (ou bool)
Use int com sinal só se o campo precisa mesmo guardar negativos, e com largura suficiente (um int x : 4 guarda de −8 a 7). E nunca escreva só int esperando sem sinal: num campo de bits, se o int "puro" tem sinal ou não é uma escolha do compilador. Escreva signed int ou unsigned int para não deixar dúvida.
6. Que tipos podem ter campos de bits
| Tipo do campo | O padrão C garante? | Observação |
|---|---|---|
unsigned int (ou só unsigned) | Sim | O mais comum. Largura de 1 a 32 no gcc e no editor. |
signed int | Sim | Guarda negativos; cuidado com largura 1. |
int | Sim | Com sinal ou não: depende do compilador. Evite. |
bool | Sim C99 | Largura 1. Ótimo para sim/não. |
unsigned char, uint8_t, unsigned long… | Não (cada compilador decide) | O gcc e o Clang aceitam; um compilador mais antigo pode recusar. |
O tipo também define a largura máxima. Um campo não pode ser mais largo que o próprio tipo:
#include <stdio.h>
struct Errado {
unsigned grande : 40;
};
int main(void) {
struct Errado e = {0};
printf("%zu\n", sizeof e);
return 0;
}
$ gcc -std=c23 -Wall -Wextra largura.c -o largura
largura.c:4:14: error: width of ‘grande’ exceeds its type
4 | unsigned grande : 40;
| ^~~~~~
Width of ‘grande’ exceeds its type = "a largura de grande passa do tamanho do tipo". Um unsigned tem 32 bits. O Clang é mais detalhado: width of bit-field 'grande' (40 bits) exceeds the width of its type (32 bits). Para 40 bits, use um tipo maior, como uint64_t (aula Inteiros de Tamanho Fixo), que o gcc e o Clang aceitam.
7. O que você não pode fazer com um campo
O menor pedaço de memória que tem endereço é o byte. Um campo de bits pode começar no meio de um byte, então ele não tem endereço próprio. Isso traz três consequências.
Não dá para usar & (nem scanf direto)
#include <stdio.h>
struct Despertador {
unsigned ativo : 1;
unsigned hora : 5;
};
int main(void) {
struct Despertador d = {1, 6};
printf("Nova hora: ");
scanf("%u", &d.hora);
printf("Hora: %u\n", d.hora);
return 0;
}
$ gcc -std=c23 -Wall -Wextra endereco.c -o endereco
endereco.c: In function ‘main’:
endereco.c:11:17: error: cannot take address of bit-field ‘hora’
11 | scanf("%u", &d.hora);
| ^
Cannot take address of bit-field ‘hora’ = "não é possível pegar o endereço do campo de bits hora". O scanf precisa de um endereço para saber onde guardar (aula scanf), e o campo não tem um. No Clang: address of bit-field requested ("foi pedido o endereço de um campo de bits"). Pelo mesmo motivo, também não existe ponteiro para um campo (unsigned *p = &d.hora; dá o mesmo erro).
O conserto: leia numa variável comum e depois copie para o campo. De quebra, você confere o valor antes, e o problema da seção 4 some.
Missão: este programa não compila. Crie uma variável unsigned h = 0;, leia nela com o scanf e, se ela for no máximo 23, guarde em d.hora. A entrada já tem o número 7; o programa tem que mostrar Hora: 7.
#include <stdio.h>
struct Despertador {
unsigned ativo : 1;
unsigned hora : 5;
};
int main(void) {
struct Despertador d = {1, 6};
printf("Nova hora: ");
scanf("%u", &d.hora);
printf("Hora: %u\n", d.hora);
return 0;
}
#include <stdio.h>
struct Despertador {
unsigned ativo : 1;
unsigned hora : 5;
};
int main(void) {
struct Despertador d = {1, 6};
unsigned h = 0;
printf("Nova hora: ");
if (scanf("%u", &h) == 1 && h <= 23) {
d.hora = h;
}
printf("Hora: %u\n", d.hora);
return 0;
}
Não dá para usar sizeof num campo
O sizeof mede em bytes, e um campo de 5 bits não tem um número inteiro de bytes:
$ cat sizeofcampo.c
#include <stdio.h>
struct D { unsigned hora : 5; };
int main(void) {
struct D d = {6};
printf("%zu\n", sizeof d.hora);
return 0;
}
$ gcc -std=c23 -Wall -Wextra sizeofcampo.c -o sizeofcampo
sizeofcampo.c: In function ‘main’:
sizeofcampo.c:7:28: error: ‘sizeof’ applied to a bit-field
7 | printf("%zu\n", sizeof d.hora);
| ^
"sizeof aplicado a um campo de bits". O sizeof d, da struct inteira, continua valendo.
Não existe array de campos de bits
unsigned luzes[8] : 1; não existe em C. Se a Ana quer 8 interruptores, ela escreve 8 campos com nomes (sala, cozinha…) ou usa um número comum e os operadores de bits (aulas Operadores de Bits e Máscaras e Flags), que permitem escolher o bit por um índice.
8. Onde cada campo fica: depende do compilador
Dentro da "gaveta", qual campo fica nos bits da direita e qual fica nos da esquerda? O padrão C não diz: cada compilador (e cada tipo de processador) escolhe. Este programa copia os bytes da struct para um unsigned comum com memcpy (aula Funções de String) e mostra o número em hexadecimal:
#include <stdio.h>
#include <string.h>
struct Tres {
unsigned a : 4;
unsigned b : 4;
unsigned c : 8;
};
int main(void) {
struct Tres t = {0};
t.a = 0x1;
t.b = 0x2;
t.c = 0xFF;
unsigned bruto = 0;
memcpy(&bruto, &t, sizeof bruto);
printf("bruto = 0x%08X\n", bruto);
return 0;
}
$ gcc -std=c23 -Wall -Wextra ordem.c -o ordem $ ./ordem bruto = 0x0000FF21
Lendo da direita para a esquerda (cada dígito hexadecimal são 4 bits): 1 é o a, 2 é o b, FF é o c. No gcc do laboratório e no Clang do editor, o primeiro campo fica nos bits mais baixos (os da direita), e os dois mostram 0x0000FF21. Em outros processadores e compiladores, a ordem pode ser a contrária, ou o compilador pode deixar espaços entre os campos.
Se os bits vão sair do programa (gravados num arquivo, enviados pela rede, escritos num registrador de um aparelho), a posição exata importa, e com campos de bits ela muda de compilador para compilador. Nesses casos, use um inteiro de tamanho fixo (uint32_t) e monte os bits você mesmo com <<, | e & (aula Máscaras e Flags). Campos de bits são ótimos para dados que ficam dentro do programa.
Campos sem nome e largura zero
Dois recursos menos usados, para quando você quer controlar o espaço:
#include <stdio.h>
struct A { unsigned x : 4; unsigned y : 4; };
struct B { unsigned x : 4; unsigned : 0; unsigned y : 4; };
struct C { unsigned x : 4; unsigned : 4; unsigned y : 4; };
int main(void) {
printf("A=%zu B=%zu C=%zu\n", sizeof(struct A), sizeof(struct B), sizeof(struct C));
return 0;
}
$ gcc -std=c23 -Wall -Wextra zero.c -o zero $ ./zero A=4 B=8 C=4
- unsigned : 0;
- Campo sem nome e de largura zero: "feche esta gaveta; o próximo campo começa numa nova". Por isso
Btem 8 bytes. - unsigned : 4;
- Campo sem nome de 4 bits: um "espaço reservado" que ninguém usa, só para empurrar o
ypara a frente.Ccontinua com 4 bytes (12 bits no total).
9. Vale a pena? Formas diferentes de guardar sim/não
Economizar 12 bytes num despertador não muda nada. Campos de bits fazem diferença quando há muitos registros: um milhão de despertadores ocupam 16 MB sem campos e 4 MB com eles. Mas cada leitura de um campo custa algumas instruções a mais (o processador precisa "recortar" os bits), e há os limites que você viu.
| Forma | Espaço | Prós | Contras |
|---|---|---|---|
Membros comuns (unsigned ativo;, bool ativo;) | Maior | Simples; tem endereço; scanf direto | Desperdiça memória |
Campos de bits (unsigned ativo : 1;) | Pequeno | Usa como membro comum, com nome | Sem &; ordem dos bits não é portátil; corte silencioso |
Um inteiro com máscaras (uint8_t flags; e flags & ATIVO) | Pequeno | Posição exata dos bits; combina várias flags numa conta | Código menos legível; exige os operadores de bits |
Qual usar: comece com membros comuns. Use campos de bits quando a memória importa (muitos registros) e os dados ficam dentro do programa. Use máscaras quando os bits saem do programa (arquivos, rede, hardware) ou quando você precisa testar várias flags de uma vez.
Quando dá errado
error: cannot take address of bit-field ‘hora’
O que significa: você usou & num campo de bits, quase sempre num scanf ou para criar um ponteiro. No Clang: address of bit-field requested.
Como consertar: leia numa variável comum (unsigned h;), confira o valor e copie: d.hora = h;. Se você precisa mesmo de ponteiro para o membro, ele não pode ser campo de bits.
warning: unsigned conversion from ‘int’ to ‘unsigned char:3’ changes value from ‘9’ to ‘1’ [-Woverflow]
O que significa: o número não cabe na largura do campo e vai ser cortado (só os bits da direita ficam). No Clang: implicit truncation from 'int' to bit-field changes value.
Como consertar: aumente a largura (com 3 bits, o máximo é 7; com 4, é 15). Lembre que, com variáveis, o corte acontece sem aviso: confira o valor antes de guardar.
-1
O que significa: o campo é int (com sinal) de largura 1, que só guarda 0 e −1. O gcc avisa comparison is always false due to limited range of data type se você comparar com 1; o Clang avisa na atribuição.
Como consertar: declare como unsigned ativo : 1; ou bool ativo : 1;.
error: width of ‘grande’ exceeds its type
O que significa: a largura pedida é maior que o número de bits do tipo (32 para unsigned).
Como consertar: diminua a largura ou use um tipo maior, como uint64_t.
error: ‘sizeof’ applied to a bit-field
O que significa: sizeof mede bytes, e um campo de bits não tem tamanho em bytes. No Clang: invalid application of 'sizeof' to bit-field.
Como consertar: meça a struct inteira (sizeof d). A largura do campo é a que você escreveu depois dos dois-pontos.
Referência rápida
| Escrita | O que faz |
|---|---|
unsigned nome : N; | Campo sem sinal de N bits: guarda de 0 a 2N − 1 |
signed int nome : N; | Campo com sinal: de −2N−1 a 2N−1 − 1 (com N = 1: só 0 e −1) |
bool nome : 1; | Campo sim/não (0 ou 1) |
unsigned : N; | N bits sem nome, reservados (espaço vazio) |
unsigned : 0; | O próximo campo começa numa nova unidade de armazenamento |
x.nome = v; | Guarda v; se não couber, ficam só os N bits da direita |
&x.nome, sizeof x.nome | Erro de compilação: campo de bits não tem endereço nem tamanho em bytes |
sizeof x | Tamanho da struct inteira (múltiplo do tamanho da unidade, 4 bytes para unsigned) |
Exercícios
1. Largura do mês
Complete com a menor largura que guarda os meses de 1 a 12:
2. Sim ou não
Complete com o tipo que guarda 0 ou 1 num campo de 1 bit sem a pegadinha do −1 (escreva um tipo de uma palavra só, sem include):
3. Um campo unsigned nivel : 3; recebe v.nivel = 10;. O que fica guardado?
4. Por que scanf("%u", &d.hora); não compila quando hora é campo de bits?
5. Uma struct tem só unsigned a : 10; unsigned b : 10;. Quanto dá o sizeof no gcc do laboratório?
6. A Ana quer gravar num arquivo um cabeçalho de 32 bits com posições de bits definidas por um documento oficial. O que usar?
Missão final: a data em 4 bytes
Missão: a agenda da Ana guarda milhares de datas, e cada uma ocupa 12 bytes. Transforme os três membros em campos de bits com a menor largura possível para cada um (dia de 1 a 31, mês de 1 a 12, ano até 4095), para a data caber em 4 bytes. A saída tem que ser:
17/10/2026 sizeof: 4
#include <stdio.h>
struct Data {
unsigned dia;
unsigned mes;
unsigned ano;
};
int main(void) {
struct Data hoje = {17, 10, 2026};
printf("%02u/%02u/%u\n", hoje.dia, hoje.mes, hoje.ano);
printf("sizeof: %zu\n", sizeof hoje);
return 0;
}
#include <stdio.h>
struct Data {
unsigned dia : 5;
unsigned mes : 4;
unsigned ano : 12;
};
int main(void) {
struct Data hoje = {17, 10, 2026};
printf("%02u/%02u/%u\n", hoje.dia, hoje.mes, hoje.ano);
printf("sizeof: %zu\n", sizeof hoje);
return 0;
}
No laboratório, a solução mostrou as mesmas duas linhas: 5 + 4 + 12 = 21 bits, uma unidade de 32 bits só. Experimente pôr ano : 11: o 2026 ainda cabe (11 bits vão até 2047), mas a agenda quebraria em 2048.
Resumo
- Campo de bits:
unsigned nome : N;dentro de umastruct. O membro ocupa só N bits, e vários campos dividem a mesma unidade (umunsignedde 32 bits). - Com N bits sem sinal cabem de 0 a 2N − 1. Escolha a menor largura em que o maior valor cabe.
- O despertador da Ana caiu de 16 para 4 bytes. A economia importa quando há muitos registros.
- Valor que não cabe é cortado (ficam os bits da direita). Com número fixo, o compilador avisa (
-Woverflow); com variável, não: confira antes. - Use
unsignedoubool. Umint x : 1só guarda 0 e −1. - Campo de bits não tem endereço (
&,scanf, ponteiro) nemsizeof, e não existe array de campos. - A posição dos campos dentro da unidade depende do compilador. Para arquivos, rede e hardware, use máscaras.