¿Cuál es el especificador de formato printf para bool?

458

Desde ANSI C99 hay _Boolo boolvía stdbool.h. Pero, ¿hay también un printfespecificador de formato para bool?

Me refiero a algo como en ese pseudocódigo:

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

que imprimiría:

true
maxschlepzig
fuente
1
Puede leer esto para obtener más información cplusplus.com/reference/cstdio/printf ¡Siempre puede hacerlo!
Varvarigos Emmanouil
3
@billinkc, mi pregunta no se trata realmente de cuál es la mejor manera de imprimir valores bool: se trata de un especificador concreto printf. Lo que no parece existir. Otro ángulo a una respuesta simple sería: tal vez hay una manera de añadir un especificador de formato personalizado a printf que realiza la conversión bool ...
maxschlepzig
Es justo, aunque parece que no tengo la capacidad de deshacer el VtC, así que tendré que esperar a que expire mi voto.
billinkc
@maxschlepzig: la única forma de resolver el problema es consultar la documentación. Si usa GNU / Linux (como ejemplo, ya que no nos contó sobre su sistema), puede leer un manual impreso actualizado en [páginas de manual de Linux] (man7.org). Si desea imprimir cadenas "verdaderas" / "falsas", puede construirlas manualmente, es bastante fácil.
Bulat M.

Respuestas:

711

No hay un especificador de formato para los booltipos. Sin embargo, dado que cualquier tipo integral más corto de lo que intse promueve intcuando se pasa a printf()los argumentos variados, puede usar %d:

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

Pero por qué no:

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

o mejor:

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

o mejor:

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

¿en lugar?

Adrian Mole
fuente
21
Haría +1 esto si se deshace de la expresión literal de cadena no única como la cadena de formato. Este tipo de uso se convierte fácilmente en un uso inseguro. printf("%s", x ? "true" : "false");solucionaría el problema
R .. GitHub DEJA DE AYUDAR A ICE
2
Para la parte "por qué no" de esta respuesta: un especificador de formato para bool permitiría que la cadena de formato se use como se diseñó: para construir una cadena con una mezcla de literales y valores.
noamtm
13
Solo como una nota, tendería a discutir que printf("%s", x ? "true" : "false");es mejor eso printf(x ? "true" : "false");: usted tiene el control total de la cadena de formato aquí, por lo que no hay peligro de que obtenga algo como "%d"lo que causaría problemas. El fputs, por otro lado, es una mejor opción.
paxdiablo
15
¿Por qué es fputs"aún mejor"? Siempre estoy buscando formas de mejorar mi C. ¿En qué circunstancias debo usar en fputslugar de printf?
Arc676
10
@ Arc676, para una cadena sin formato, fputs es más rápido y sencillo que printf (que tiene que analizar la cadena buscando caracteres de formato). El uso de fputs (stdout) en lugar de solo put () (que por defecto es stdout) elimina la nueva línea que pone () se agrega a la salida.
Chad
45

No hay un especificador de formato para bool. Puede imprimirlo utilizando algunos de los especificadores existentes para imprimir tipos integrales o hacer algo más elegante:

 printf("%s", x?"true":"false");
Ivaylo Strandjev
fuente
El yeso no es necesario.
@ H2CO3 de todos modos, he sugerido una solución para imprimir "verdadero" y "falso" como solicitudes de OP. También he cambiado ligeramente mi redacción en la parte que mencionas.
Ivaylo Strandjev
55
@IvayloStrandjev: Sí, no es un booltipo en C, pero no en la edición C89 - es parte de la especificación lenguaje C99. Hay una nueva palabra clave _Bool, y si la incluye <stdbool.h>, entonces booles sinónimo de _Bool.
Adam Rosenfield
30

ANSI C99 / C11 no incluye un especificador de conversión de printf adicional para bool.

Pero la biblioteca GNU C proporciona una API para agregar especificadores personalizados .

Un ejemplo:

#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;
}

Como es una extensión glibc, el GCC advierte sobre ese especificador personalizado:

$ gcc -Wall -g main.c -o main
main.c: En la función 'main':
main.c: 34: 3: advertencia: carácter de tipo de conversión desconocido 'B' en formato [-Wformat =]
   r = printf ("El resultado es:% B \ n", b);
   ^
main.c: 34: 3: advertencia: demasiados argumentos para el formato [-Wformat-extra-args]

Salida:

$ ./main
El resultado es: falso
(escrito 21 caracteres)
$ ./principal 1
El resultado es: verdadero
(escrito 20 caracteres)
maxschlepzig
fuente
12

En la tradición de itoa():

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

bool x = true;
printf("%s\n", btoa(x));
jxh
fuente
55
btoaes "cadena binaria a cadena base 64" en JavaScript no estándar (Gecko y WebKit), por lo que es posible que desee utilizar un nombre diferente.
panzi
26
@panzi: No estoy seguro de que valga la pena que un programador de C se preocupe por los identificadores de JavaScript no estándar.
Keith Thompson
55
@KeithThompson Creo que confundí las preguntas y de alguna manera pensé que se trataba de JavaScript, lo que no tiene sentido de todos modos. Probablemente ya era tarde en la noche.
panzi
99
O, para los más tortuosos entre nosotros: "true\0false"[(!x)*5]:-)
paxdiablo
1
@ MoooDuck: tal vez !!x*5.
jxh
4

No puedes, pero puedes imprimir 0 o 1

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

fuente

Stephan
fuente
2

Si te gusta C ++ mejor que C, puedes probar esto:

#include <ios>
#include <iostream>

bool b = IsSomethingTrue();
std::cout << std::boolalpha << b;
Arsen YM
fuente
55
Esta respuesta está fuera de tema y debe eliminarse, ya que se trata de otro idioma que el de la pregunta.
Lundin
2
@Lundin No estoy de acuerdo con que esto deba eliminarse. El objetivo de SO no es solo ayudar a una persona, sino ayudar a todas las personas con la misma pregunta. Cuando busco sprintf print boolean como verdadero falso c ++ , esta es la primera página que aparece (aunque podría decirse que esta página podría haber sido el mejor resultado si esta respuesta no existiera). Como C ++ es casi un superconjunto de C, no creo que tales respuestas se deban descartar tan fácilmente. +1 de mi parte
Jeff G
1
@JeffG Sí, tales respuestas deben eliminarse, tenemos políticas muy claras. Lea los wikis de etiquetas C y C ++. Esta pregunta no es útil para los programadores de C, particularmente porque los sistemas booleanos de C y C ++ son completamente diferentes y la pregunta está etiquetada con C. Que Google no puede entender los dos ++ finales en su búsqueda no es un problema de SO.
Lundin
2
@Lundin Mi comentario no fue interpretado como un comentario sobre las políticas de SO. Realmente fue un comentario sobre si esta respuesta se agrega constructivamente a la pregunta. Esta respuesta es inmediatamente identificable como C ++, solo. Nadie que venga aquí por una respuesta de solo C se engañará pensando que esto funcionaría en C y perdería el tiempo probándolo. Sin embargo, esta es una gran respuesta para C ++. Si las respuestas son útiles, incluso si no ayudan al OP, ¿no deberían guardarse? Creo que las respuestas constructivas que tienen advertencias claramente identificadas nunca deberían eliminarse, independientemente de la política.
Jeff G
1
@JeffG Puede mencionarlo en meta.stackoverflow.com , este no es el lugar para tener esta discusión.
Lundin
2

Para imprimir solo 1 o 0 en función del valor booleano que acabo de usar:

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

Especialmente útil con Banderas:

#define MY_FLAG (1 << 4)
int flags = MY_FLAG;
printf("%d\n", !!(flags & MY_FLAG));
Tarion
fuente
Tenga en cuenta que el poder !!podría optimizarse lejos
ragerdl
1

Prefiero una respuesta de Mejor manera de imprimir el resultado de un bool como 'falso' o 'verdadero' en c? , al igual que

printf("%s\n", "false\0true"+6*x);
  • x == 0, "falso \ 0 verdadero" + 0 "significa" falso ";
  • x == 1, "falso \ 0 verdadero" + 6 "significa" verdadero ";
xjzhou
fuente
21
Esto es totalmente incomprensible. Me llevó un buen rato descubrir lo que "false\0true"+6*xrealmente hacía. Si trabaja en un proyecto con otras personas, o simplemente en un proyecto con una base de código que desea comprender x años más tarde, se evitarán construcciones como esta.
HelloGoodbye
3
Aunque veo que esto podría estar más optimizado ya que no tiene ramificaciones. Si le preocupa la velocidad, esta podría ser una opción, solo asegúrese de explicar bien la mecánica detrás del truco en un comentario. Una función o macro en línea con un nombre autodocumentado también sería útil (pero probablemente no sea suficiente en este caso).
HelloGoodbye
3
Además de las preocupaciones sobre la legibilidad, tenga en cuenta que esto explotará si alguien pasa un valor que no sea 0 o 1.
enchufe el
2
@plugwash Por supuesto, podría cambiarlo a printf("%s\n","false\0true"+6*(x?1:0));solo 5% menos legible.
hoosierEE
static inline char const *bool2str(_Bool b) { return "false\0true"+6*x; } int main(void) { printf("%s != %s", bool2str(false), bool2str(true)); return 0; } Igual que con static inline char decimal2char(int d) { assert(d >= 0 && d <= 9); return '0' + d; }; simplemente envuélvalo en una función con nombre descriptivo y no se preocupe por su legibilidad.
yyny