Qual é o especificador de formato printf para bool?

458

Desde ANSI C99, existe _Boolou boolvia stdbool.h. Mas há também um printfespecificador de formato para bool?

Quero dizer algo como nesse pseudo código:

bool x = true;
printf("%B\n", x);

que imprimiria:

true
maxschlepzig
fonte
1
Você pode ler isso para obter mais informações cplusplus.com/reference/cstdio/printf Você sempre pode fazer isso!
Varvarigos Emmanouil
3
@ Billinkc, minha pergunta não é realmente sobre qual é a melhor maneira de imprimir valores bool - é sobre um especificador concreto printf. O que parece não existir. Outro ângulo para uma resposta boa seria: talvez haja uma maneira de adicionar um especificador de formato personalizado para printf que faz a conversão bool ...
maxschlepzig
É justo, embora eu não pareça ter a capacidade de cancelar a transmissão do VtC, então terei que esperar que meu voto expire.
billinkc
@maxschlepzig: a única maneira de resolver o problema é verificar a documentação. Se você usa o GNU / Linux (como exemplo, como você não nos falou sobre o seu sistema), pode ler um manual de impressão atualizado em [páginas de manual do Linux] (man7.org). Se você deseja que as strings "true" / "false" sejam impressas, é possível construí-las manualmente, é muito fácil.
quer

Respostas:

711

Não há especificador de formato para booltipos. No entanto, como qualquer tipo de integrante menor que o intpromovido intquando transmitido aos printf()argumentos variados, você pode usar %d:

bool x = true;
printf("%d\n", x); // prints 1

Mas porque não:

printf(x ? "true" : "false");

ou melhor:

printf("%s", x ? "true" : "false");

ou, melhor ainda:

fputs(x ? "true" : "false", stdout);

em vez de?

Adrian Mole
fonte
21
Eu marcaria isso com +1 se você se livrar da expressão literal de cadeia não única como a cadeia de formato. Esse tipo de uso se transforma facilmente em uso inseguro. printf("%s", x ? "true" : "false");resolveria o problema.
R .. GitHub PARE DE AJUDAR O GELO
2
Para a parte "por que não" desta resposta - um especificador de formato para bool permitiria que a string de formato fosse usada como projetada: para construir uma string com uma mistura de literais e valores.
noamtm
13
Apenas como uma observação, eu tenderia a disputar que printf("%s", x ? "true" : "false");é melhor do que isso printf(x ? "true" : "false");- você está no controle total da cadeia de caracteres de formato aqui, para que não haja perigo de obter algo como o "%d"que causaria problemas. O fputs, por outro lado, é uma opção melhor.
paxdiablo
15
Por que é fputs"ainda melhor"? Estou sempre procurando maneiras de melhorar meu C. Em que circunstâncias devo usar em fputsvez de printf?
precisa saber é o seguinte
10
@ Arc676, para uma sequência sem formatação, a saída é mais rápida e mais simples que o printf (que precisa analisar a sequência procurando caracteres de formatação). O uso de fputs (stdout) em vez de apenas puts () (cujo padrão é stdout) elimina a nova linha que coloca () anexa à saída.
Chad
45

Não há especificador de formato para bool. Você pode imprimi-lo usando alguns dos especificadores existentes para imprimir tipos integrais ou fazer algo mais sofisticado:

 printf("%s", x?"true":"false");
Ivaylo Strandjev
fonte
O elenco não é necessário.
@ H2CO3 de qualquer maneira, sugeri uma solução imprimindo "true" e "false" conforme solicitações de OP. Também mudei levemente minha redação na parte que você mencionou.
Ivaylo Strandjev
5
@IvayloStrandjev: Sim, há é um booltipo em C, não apenas na edição C89 - é parte da especificação linguagem C99. Há uma nova palavra-chave _Boole, se você incluir <stdbool.h>, boolé sinônimo de _Bool.
Adam Rosenfield
30

O ANSI C99 / C11 não inclui um especificador de conversão extra para bool.

Mas a biblioteca GNU C fornece uma API para adicionar especificadores personalizados .

Um exemplo:

#include <stdio.h>
#include <printf.h>
#include <stdbool.h>

static int bool_arginfo(const struct printf_info *info, size_t n,
    int *argtypes, int *size)
{
  if (n) {
    argtypes[0] = PA_INT;
    *size = sizeof(bool);
  }
  return 1;
}
static int bool_printf(FILE *stream, const struct printf_info *info,
    const void *const *args)
{
  bool b =  *(const bool*)(args[0]);
  int r = fputs(b ? "true" : "false", stream);
  return r == EOF ? -1 : (b ? 4 : 5);
}
static int setup_bool_specifier()
{
  int r = register_printf_specifier('B', bool_printf, bool_arginfo);
  return r;
}
int main(int argc, char **argv)
{
  int r = setup_bool_specifier();
  if (r) return 1;
  bool b = argc > 1;
  r = printf("The result is: %B\n", b);
  printf("(written %d characters)\n", r);
  return 0;
}

Por se tratar de extensões glibc, o GCC alerta sobre esse especificador personalizado:

$ gcc -Wall -g main.c -o principal
main.c: Na função 'main':
main.c: 34: 3: aviso: caractere de tipo de conversão desconhecido 'B' no formato [-Wformat =]
   r = printf ("O resultado é:% B \ n", b);
   ^
main.c: 34: 3: aviso: muitos argumentos para o formato [-Wformat-extra-args]

Resultado:

$ ./main
O resultado é: false
(escritos 21 caracteres)
$ ./main 1
O resultado é: true
(escritos 20 caracteres)
maxschlepzig
fonte
12

Na tradição de itoa():

#define btoa(x) ((x)?"true":"false")

bool x = true;
printf("%s\n", btoa(x));
jxh
fonte
5
btoaé "string binária para a base da string 64" em JavaScript não padrão (Gecko e WebKit), portanto, convém usar um nome diferente.
Panzi # 29/13
26
@panzi: Não sei se vale a pena o esforço de um programador C se preocupar com identificadores JavaScript não padrão.
21314 Keith Thompson
5
@KeithThompson Acho que confundi as perguntas e de alguma forma pensei que isso era sobre JavaScript, o que não faz sentido de qualquer maneira. Provavelmente já era tarde da noite.
panzi
9
Ou, para os mais desonestos entre nós: "true\0false"[(!x)*5]:-)
paxdiablo 15/10
1
@MooingDuck: talvez !!x*5.
Jxh #
4

Você não pode, mas pode imprimir 0 ou 1

_Bool b = 1;
printf("%d\n", b);

fonte

Stephan
fonte
2

Se você gosta de C ++ melhor que C, pode tentar o seguinte:

#include <ios>
#include <iostream>

bool b = IsSomethingTrue();
std::cout << std::boolalpha << b;
Arsen YM
fonte
5
Esta resposta está fora do tópico e deve ser excluída, pois é sobre outro idioma que não o da pergunta.
Lundin
2
@Lundin Não concordo que isso deva ser excluído. O objetivo do SO não é apenas ajudar uma pessoa, mas ajudar todas as pessoas com a mesma pergunta. Quando procuro sprintf print boolean como true false c ++ , esta é a primeira página que aparece (embora, sem dúvida, essa página possa ter sido o resultado principal se essa resposta não existisse). Como C ++ é quase um superconjunto de C, não acho que essas respostas devam ser descartadas com tanta facilidade. +1 de mim.
Jeff G
1
@ Jeffff Sim, essas respostas devem ser excluídas, temos políticas muito claras. Leia as wikis das tags C e C ++. Esta pergunta não é útil para programadores de C, principalmente porque os sistemas booleanos de C e C ++ são completamente diferentes e a pergunta está marcada com C. O Google não é capaz de entender os dois ++ à direita em sua pesquisa não é um problema da SO.
Lundin
2
@Lundin Meu comentário não pretendia ser interpretado como um comentário sobre as políticas da SO. Foi realmente um comentário sobre se essa resposta adiciona construtivamente à pergunta. Esta resposta é imediatamente identificável como somente C ++. Ninguém vindo aqui para obter uma resposta somente C seria enganado a pensar que isso funcionaria em C e perderia tempo tentando. No entanto, esta é uma ótima resposta para C ++. Se as respostas são úteis, mesmo que não ajudem o OP, elas não devem ser mantidas? Acho que respostas construtivas que identificaram claramente advertências nunca devem ser excluídas, independentemente da política.
Jeff G
1
@JeffG Você pode acessá-lo em meta.stackoverflow.com , este não é o lugar para discussões.
Lundin
2

Para imprimir apenas 1 ou 0 com base no valor booleano que acabei de usar:

printf("%d\n", !!(42));

Especialmente útil com bandeiras:

#define MY_FLAG (1 << 4)
int flags = MY_FLAG;
printf("%d\n", !!(flags & MY_FLAG));
Tarion
fonte
Tenha em atenção que o !!pode ficar otimizadas
ragerdl
1

Prefiro uma resposta da Melhor maneira de imprimir o resultado de um bool como 'false' ou 'true' em c? , Assim como

printf("%s\n", "false\0true"+6*x);
  • x == 0, "falso \ 0 verdadeiro" + 0 "significa" falso ";
  • x == 1, "falso \ 0 verdadeiro" + 6 "significa" verdadeiro ";
xjzhou
fonte
21
Isso é totalmente incompreensível. Levei um bom tempo antes de descobrir o que "false\0true"+6*xrealmente fazia. Se você trabalha em um projeto com outras pessoas ou apenas em um projeto com uma base de código que deseja entender x anos depois, construções como essa devem ser evitadas.
hellogoodbye
3
Embora eu veja que isso pode ser mais otimizado, pois é sem ramo. Se a velocidade é sua preocupação, isso pode ser uma opção, apenas certifique-se de explicar bem a mecânica por trás do truque em um comentário. Uma função embutida ou macro com um nome de auto-documentação também seria útil (mas provavelmente não suficiente neste caso).
hellogoodbye
3
Bem como as preocupações com urso legibilidade em mente que isso vai explodir se alguém passa em um valor diferente de 0 ou 1.
plugwash
2
@ plugwash É claro que você pode alterá-lo para o printf("%s\n","false\0true"+6*(x?1:0));que é apenas ... 5% menos legível.
precisa saber é o seguinte
static inline char const *bool2str(_Bool b) { return "false\0true"+6*x; } int main(void) { printf("%s != %s", bool2str(false), bool2str(true)); return 0; } O mesmo que com static inline char decimal2char(int d) { assert(d >= 0 && d <= 9); return '0' + d; }; apenas envolva-o em uma função com nome descritivo e não se preocupe com a legibilidade.
yyny 08/02