C Booleanos (bool)
Muitas perguntas de um programa têm só duas respostas: o cliente pagou? Está chovendo? A senha está certa? A nota é maior que 7? Para guardar essas respostas existe o tipo bool, que só tem dois valores: true (verdadeiro) e false (falso). Ele parece o tipo mais simples de todos, e é, mas em C tem uma história curiosa (por 27 anos ele nem existiu) e algumas surpresas: o printf o mostra como 1 e 0, e qualquer número pode virar bool. Os booleanos são a base de todas as decisões (if) e repetições (while) que vêm depois.
- Como criar variáveis
boolcomtrueefalseC23. - Por que o
printfmostra 1 e 0, e como mostrar "sim" e "não". - Que uma comparação (
>,==…) pode ser guardada numbool. - Como números viram
bool(zero é falso, o resto é verdadeiro), e o caminho inverso. - A história:
intno C antigo,_Boolestdbool.hdo C99 ao C17, e o código antigo que não compila no C23. - Como dar bons nomes a variáveis
bool, e por que não ler umboolcomscanf.
Os programas foram compilados na máquina fictícia da Ana com o comando padrão do guia, gcc -std=c23 -Wall -Wextra (gcc 15.2), na pasta ~/c/bool.
A ideia: o interruptor
Um interruptor de luz tem duas posições: ligado ou desligado. Não existe "meio ligado". Um bool é um interruptor guardado na memória: true é ligado, false é desligado.
O nome vem de George Boole, um matemático inglês do século XIX que criou uma álgebra só com "verdadeiro" e "falso" (a "álgebra booleana"). Cem anos depois, ela virou a base dos circuitos de todo computador.
1. true, false e o que o printf mostra
#include <stdio.h>
int main(void) {
bool chovendo = true;
bool pago = false;
printf("chovendo: %d\n", chovendo);
printf("pago: %d\n", pago);
printf("pago: %s\n", pago ? "sim" : "não");
printf("tamanho: %zu byte\n", sizeof(bool));
return 0;
}
$ gcc -std=c23 -Wall -Wextra bool.c -o bool $ ./bool chovendo: 1 pago: 0 pago: não tamanho: 1 byte
- bool chovendo = true;
- Uma variável
boolcom o valor verdadeiro.bool,trueefalsesão palavras da linguagem desde o C23: não precisam de#include. Escrevem-se em minúsculas e sem aspas ("true"seria um texto; veja a seção 4). - printf("…%d…", chovendo)
- O
printfnão tem uma lacuna que escreva "true". Umboolvai na lacuna%d, como um número:trueaparece como1efalsecomo0. É herança do C antigo, em que "verdadeiro" e "falso" eram só os números 1 e 0 (seção 5). - pago ? "sim" : "não"
- Para mostrar uma palavra, escolha o texto conforme o valor: "se
pago, o texto"sim"; senão,"não"". O? :é o operador ternário, que tem aula própria (Operador Ternário); por enquanto, use-o como uma receita, com%s. Pode trocar por"true" : "false","ligado" : "desligado", o que quiser. - sizeof(bool)
- Um
boolocupa 1 byte (aula Tamanho dos Tipos), embora só precisasse de 1 bit: o byte é o menor pedaço de memória que o computador consegue endereçar.
%b?
O C23 trouxe ao printf a lacuna %b, que mostra um número em binário (base 2): no gcc, printf("%b\n", 5) mostra 101, e um bool verdadeiro sai 1. Não é "true" em palavras, e a biblioteca C do editor do guia ainda não conhece o %b (a linha sai vazia). Para booleanos, fique com %d ou com o ? :.
Missão: o programa mostra Estoque vazio? 0. Use a receita do ? : com %s para ele mostrar Estoque vazio? não.
#include <stdio.h>
int main(void) {
bool estoque_vazio = false;
printf("Estoque vazio? %d\n", estoque_vazio);
return 0;
}
#include <stdio.h>
int main(void) {
bool estoque_vazio = false;
printf("Estoque vazio? %s\n", estoque_vazio ? "sim" : "não");
return 0;
}
2. Comparações cabem num bool
Você raramente escreve true ou false à mão. Quase sempre, um bool nasce de uma pergunta: uma comparação.
#include <stdio.h>
int main(void) {
int idade = 17;
bool maior_de_idade = idade >= 18;
bool adolescente = idade >= 13 && idade <= 19;
printf("maior de idade: %d\n", maior_de_idade);
printf("adolescente: %d\n", adolescente);
printf("idade == 17: %d\n", idade == 17);
printf("idade != 17: %d\n", idade != 17);
return 0;
}
$ gcc -std=c23 -Wall -Wextra compara.c -o compara $ ./compara maior de idade: 0 adolescente: 1 idade == 17: 1 idade != 17: 0
- idade >= 18
- "
idadeé maior ou igual a 18?" O C calcula a resposta (0, falso, porque 17 não é) e a guarda emmaior_de_idade. - idade >= 13 && idade <= 19
- Duas perguntas ligadas por
&&("e"): só é verdadeiro se as duas forem. Os operadores lógicos (&&,||,!) têm aula própria: Operadores Lógicos. - idade == 17
- "É igual a 17?" Dois sinais de igual: um só (
=) guardaria 17 na variável (aula Avisos). - idade != 17
- "É diferente de 17?"
Um detalhe do C: a resposta de uma comparação é, tecnicamente, um int que vale 1 ou 0, não um bool (aula Operadores de Comparação). Na prática, tanto faz: guardada num bool, ela vira true ou false. Prefira bool para guardar respostas de sim ou não: o tipo já diz ao leitor o que a variável é.
3. Números viram bool (e vice-versa)
O C converte números em bool sozinho, com uma regra só: zero é false; qualquer outro valor é true. E no caminho inverso, true vira 1 e false vira 0.
#include <stdio.h>
int main(void) {
bool a = 0;
bool b = 1;
bool c = -7;
bool d = 0.0;
bool e = 0.5;
printf("%d %d %d %d %d\n", a, b, c, d, e);
int f = 0.5;
bool g = 2;
int h = 2;
printf("int 0.5 = %d, bool 2 = %d, int 2 = %d\n", f, g, h);
printf("true + true = %d\n", true + true);
return 0;
}
$ gcc -std=c23 -Wall -Wextra converte.c -o converte $ ./converte 0 1 1 0 1 int 0.5 = 0, bool 2 = 1, int 2 = 2 true + true = 2
| Valor | Num bool vira | Por quê |
|---|---|---|
0, 0.0 | false (0) | Zero é o único "falso". |
1, -7, 0.5, 2 | true (1) | Diferente de zero. Até o negativo e o 0,5. |
true numa conta ou num int | 1 | Por isso true + true deu 2. |
false numa conta ou num int | 0 |
Repare na segunda linha da saída, que mostra a diferença entre bool e int:
int f = 0.5;deu 0: ointjoga fora a parte depois da vírgula (aula Conversão de Tipos). Jábool e = 0.5;deu 1: 0,5 não é zero, então é verdadeiro.bool g = 2;guardou 1, eint h = 2;guardou 2. Umboolsó guarda 0 ou 1, nunca outro número. Por isso, para "sim ou não", ele é mais seguro que umint: não existe um "sim" valendo 2.
O gcc não avisou nada. O Clang, no editor do guia, avisa as duas conversões de 0.5: implicit conversion from 'double' to 'bool' changes value from 0.5 to true [-Wliteral-conversion] ("conversão implícita de double para bool muda o valor de 0.5 para true").
Essa regra é a mesma que o if usa: if (estoque) quer dizer "se o estoque não for zero" (aula Operadores Lógicos). E é por isso que as funções de ctype.h, como isdigit, podem devolver 2048 para dizer "sim" (no Linux, isdigit('7') vale 2048): qualquer número diferente de zero é verdadeiro. Guardado num bool, o 2048 vira 1 (aula Classificar Caracteres).
Missão: o programa antigo da Ana usava um int como interruptor, e alguém guardou 2 nele: a saída é Ligado: 2, que não faz sentido. Troque o tipo de ligado para bool (sem mudar o = 2) e rode: o que aparece agora?
#include <stdio.h>
int main(void) {
int ligado = 2;
printf("Ligado: %d\n", ligado);
return 0;
}
#include <stdio.h>
int main(void) {
bool ligado = 2;
printf("Ligado: %d\n", ligado);
return 0;
}
4. A pegadinha do texto "false"
$ cat texto.c
#include <stdio.h>
int main(void) {
bool resposta = "false";
printf("%d\n", resposta);
return 0;
}
$ gcc -std=c23 -Wall -Wextra texto.c -o texto
$ ./texto
1 « o texto "false" virou verdadeiro!
Sem aviso nenhum, nem do gcc nem do Clang. O texto "false" (com aspas) não é o valor false: é um texto guardado em algum lugar da memória, e o C converteu o endereço desse lugar (que não é zero) em verdadeiro. Endereços são assunto de Ponteiros. A lição: true e false nunca levam aspas.
5. A história: int, _Bool, stdbool.h e o C23
Você vai encontrar booleanos escritos de três jeitos, conforme a idade do código:
| Época | Como se escrevia | Observação |
|---|---|---|
| C89 / C90 | int pago = 1; ou #define TRUE 1 | Não havia tipo booleano: usava-se int, com 0 e 1 (e cada programa inventava os seus nomes). |
| C99 ao C17 | #include <stdbool.h> e bool pago = true; | O tipo de verdade se chamava _Bool (um nome feio de propósito, para não quebrar programas que já usavam a palavra bool). O cabeçalho stdbool.h criava os apelidos bool, true e false. |
| C23 | bool pago = true; | bool, true e false são palavras da linguagem. O stdbool.h ainda existe, para o código antigo continuar compilando, mas não é mais necessário. |
Código do C99 continua compilando no C23, e o contrário funciona com o stdbool.h:
#include <stdio.h>
#include <stdbool.h>
int main(void) {
bool pronto = true;
_Bool velho = 1;
printf("%d %d\n", pronto, velho);
return 0;
}
$ gcc -std=c23 -Wall -Wextra c99.c -o c99 && ./c99 1 1 $ gcc -std=c17 -Wall -Wextra c99.c -o c99 && ./c99 1 1
Sem o #include <stdbool.h>, com -std=c17, o bool é um nome desconhecido (unknown type name ‘bool’); a aula Versões do C mostra esse erro e tem uma missão sobre ele. O _Bool funciona em todas as versões desde o C99, mas ninguém escreve assim em código novo.
Código antigo que inventou o próprio bool
Antes do C99, muitos programas criavam o próprio tipo booleano. No C23, isso quebra, porque bool, true e false agora são palavras reservadas:
#include <stdio.h>
typedef enum { false, true } bool;
int main(void) {
bool pronto = true;
printf("%d\n", pronto);
return 0;
}
$ gcc -std=c23 -Wall -Wextra antigo.c -o antigo
antigo.c:3:16: error: cannot use keyword ‘false’ as enumeration constant
3 | typedef enum { false, true } bool;
| ^~~~~
antigo.c:3:16: note: ‘false’ is a keyword with ‘-std=c23’ onwards
antigo.c:3:30: error: expected ‘;’, identifier or ‘(’ before ‘bool’
3 | typedef enum { false, true } bool;
| ^~~~
antigo.c:3:30: warning: useless type name in empty declaration
$ gcc -std=c17 -Wall -Wextra antigo.c -o antigo && ./antigo
1
A linha 3 (com typedef e enum, assuntos das aulas typedef e Enums) cria um tipo chamado bool com os valores false e true. O gcc explica: "não é possível usar a palavra-chave false como constante de enumeração", e a nota: "false é palavra-chave a partir de -std=c23". Com -std=c17, compila. Conserto, se o código for seu: apague a linha 3 e use o bool da linguagem. Se for um programa antigo de outra pessoa, compile-o com -std=c17.
6. Bons nomes para bool
Uma variável bool responde a uma pergunta de sim ou não. Dê a ela um nome que soe como a pergunta (ou a afirmação), para que o código se leia como uma frase. No estilo do guia, o snake_case (aula Nomes de Variáveis):
| Ruim | Bom | Lê-se |
|---|---|---|
bool status; | bool pago; | "pago?" |
bool flag; | bool tem_estoque; | "tem estoque?" |
bool idade; | bool maior_de_idade; | "é maior de idade?" |
bool chuva; | bool esta_chovendo; | "está chovendo?" |
bool nao_ativo; | bool ativo; | Evite nomes negativos: "não não ativo" confunde. |
Para onde o bool vai
Até aqui, você só mostrou booleanos. O verdadeiro uso deles é decidir: o if executa um trecho só se a condição for verdadeira, e o while repete enquanto ela for. Um gostinho do que vem em if e else:
$ cat gostinho.c
#include <stdio.h>
int main(void) {
bool pago = true;
if (pago) {
printf("Pode retirar o pedido.\n");
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra gostinho.c -o gostinho
$ ./gostinho
Pode retirar o pedido.
Com um bom nome, if (pago) se lê "se pago". Troque true por false, e a frase não aparece.
Quando dá errado
bool com scanf("%d"): stack smashing detected
$ cat lebool.c
#include <stdio.h>
int main(void) {
bool pago = false;
printf("Pagou? (1 = sim, 0 = não) ");
scanf("%d", &pago);
printf("pago = %d\n", pago);
return 0;
}
$ gcc -std=c23 -Wall -Wextra lebool.c -o lebool
lebool.c: In function ‘main’:
lebool.c:6:13: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘_Bool *’ [-Wformat=]
6 | scanf("%d", &pago);
| ~^ ~~~~~
| | |
| | _Bool *
| int *
$ echo 1 | ./lebool
Pagou? (1 = sim, 0 = não) pago = 1
*** stack smashing detected ***: terminated
Abortado (imagem do núcleo gravada) echo 1 | ./lebool
O que significa: o %d do scanf escreve um int inteiro (4 bytes) no endereço que recebeu, mas o bool só tem 1 byte. Os outros 3 bytes foram escritos por cima da memória vizinha, e a proteção do gcc percebeu no fim do programa: "esmagamento da pilha detectado" (a pilha é a área da memória das variáveis; aula Pilha e Heap). O aviso já dizia: %d espera int *, e veio _Bool * (o nome verdadeiro do bool). No editor do guia, o mesmo programa roda sem cair, o que é pior: o estrago acontece em silêncio.
Como consertar: não existe formato do scanf para bool. Leia num int e converta: int resposta = 0; scanf("%d", &resposta); bool pago = resposta; (aula Entrada com scanf).
printf mostra 1 e 0 em vez de true e false
O que significa: é o comportamento normal: o printf não tem uma lacuna para bool em palavras.
Como consertar: printf("%s\n", pago ? "true" : "false"); (ou "sim"/"não").
bool deu verdadeiro quando deveria ser falso
O que significa: ele recebeu um número diferente de zero (até 0,5 ou −1), ou um texto entre aspas ("false"), que sempre vira verdadeiro.
Como consertar: use true/false sem aspas, ou uma comparação: bool tem_estoque = estoque > 0;.
unknown type name ‘bool’
O que significa: o código está sendo compilado com um C anterior ao C23 (-std=c17, -std=c99, ou um compilador antigo, como o gcc 13 e anteriores, que não usam o C23 por padrão).
Como consertar: compile com -std=c23, ou acrescente #include <stdbool.h> no topo (funciona nos dois).
cannot use keyword ‘false’ as enumeration constant
O que significa: um código antigo criou o próprio bool, true ou false, e no C23 essas palavras já são da linguagem (seção 5).
Como consertar: apague as definições antigas, ou compile esse programa com -std=c17.
Referência rápida
| Escrita | O que faz |
|---|---|
bool pago = true; | Variável booleana C23 (no C99 ao C17, com #include <stdbool.h>) |
printf("%d", pago); | Mostra 1 ou 0 |
printf("%s", pago ? "sim" : "não"); | Mostra uma palavra conforme o valor |
bool b = x > 10; | Guarda o resultado de uma comparação |
bool b = numero; | 0 → false; qualquer outro → true |
int n = true; | true → 1; false → 0 |
sizeof(bool) | 1 (byte) |
_Bool | O nome antigo do tipo (C99); ainda funciona |
Exercícios
1. O valor falso
Complete com o valor booleano "falso":
2. O cabeçalho antigo
No C99 ao C17, que cabeçalho é preciso incluir para escrever bool, true e false?
3. Em palavras
Complete para mostrar sim ou não:
4. O que printf("%d\n", 3 < 2); mostra?
5. Quanto vale bool b = -3; quando mostrado com %d?
6. E bool b = "false";?
7. Qual é o jeito seguro de ler "sim ou não" do teclado para um bool?
Missão final: votar e dirigir
Missão: o Bruno tem 17 anos. Crie duas variáveis bool: pode_votar (no Brasil, a partir de 16 anos) e pode_dirigir (a partir de 18), cada uma calculada com uma comparação usando idade. Mostre as duas em palavras, sem nenhum aviso:
Pode votar: sim Pode dirigir: não
#include <stdio.h>
int main(void) {
int idade = 17;
// crie pode_votar e pode_dirigir
// mostre as duas em palavras
return 0;
}
#include <stdio.h>
int main(void) {
int idade = 17;
bool pode_votar = idade >= 16;
bool pode_dirigir = idade >= 18;
printf("Pode votar: %s\n", pode_votar ? "sim" : "não");
printf("Pode dirigir: %s\n", pode_dirigir ? "sim" : "não");
return 0;
}
Resumo
boolguardatrueoufalse(sem aspas) e ocupa 1 byte. No C23, são palavras da linguagem; do C99 ao C17, vêm do#include <stdbool.h>(o tipo de verdade é o_Bool).- O
printfmostra umboolcom%d: 1 ou 0. Para palavras,pago ? "sim" : "não"com%s. - Uma comparação (
==,!=,<,>,<=,>=) vale 1 ou 0 e pode ser guardada numbool. - Zero vira
false; qualquer outro número (até −7 e 0,5) viratrue.truenuma conta vale 1. Umboolnunca guarda outro número. - Um texto entre aspas, até
"false", viratrue. - Código antigo que criou o próprio
boolnão compila no C23: use o da linguagem, ou-std=c17. - Não leia um
boolcomscanf("%d"): leia numint. - Dê nomes que soem como perguntas:
pago,tem_estoque,esta_chovendo.