Qual è l'identificatore del formato printf per bool?


458

Da ANSI C99 esiste _Boolo boolvia stdbool.h. Ma esiste anche un printfidentificatore di formato per bool?

Intendo qualcosa di simile a quello pseudo codice:

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

che stamperebbe:

true

1
Puoi leggere questo per ulteriori informazioni cplusplus.com/reference/cstdio/printf Puoi comunque farlo!
Varvarigos Emmanouil,


3
@billinkc, la mia domanda non riguarda davvero quale sia il modo migliore per stampare valori bool: si tratta di un identificatore concreto di printf. Che non sembra esistere. Un altro angolo di una bella risposta potrebbe essere: forse c'è un modo per aggiungere un
identificatore di

Abbastanza giusto, sebbene non sembri avere la possibilità di annullare la registrazione del VtC, quindi dovrò solo aspettare che il mio voto scada.
billinkc,

@maxschlepzig: l'unico modo per risolvere il problema è controllare la documentazione. Se usi GNU / Linux (come esempio, dal momento che non ci hai parlato del tuo sistema), puoi leggere un manuale di printf aggiornato su [pagine man di Linux] (man7.org). Se vuoi ottenere le stringhe "true" / "false", puoi costruirle manualmente, è abbastanza facile.
Bulat M.,

Risposte:


711

Non esiste un identificatore di formato per i booltipi. Tuttavia, poiché qualsiasi tipo integrale più breve di quello che intviene promosso intquando trasmesso agli printf()argomenti variadici, è possibile utilizzare %d:

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

Ma perchè no:

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

o meglio:

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

o, ancora meglio:

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

anziché?


21
Lo farei +1 se ti sbarazzassi dell'espressione letterale non a stringa singola come stringa di formato. Questo tipo di utilizzo si trasforma facilmente in un utilizzo non sicuro. printf("%s", x ? "true" : "false");risolverebbe il problema.
R .. GitHub smette di aiutare ICE il

2
Per la parte "why not" di questa risposta - un identificatore di formato per bool consentirebbe di utilizzare la stringa di formato come progettato: per costruire una stringa con un misto di valori letterali e valori.
Noamtm,

13
Proprio come una nota, mi tendo verso contestazione che printf("%s", x ? "true" : "false");è meglio che printf(x ? "true" : "false");- si è in totale controllo della stringa di formato qui quindi non c'è alcun pericolo che otterrà qualcosa di simile "%d"che causerebbe problemi. La fputs, d'altra parte, è una scelta migliore.
paxdiablo,

15
Perché fputs"ancora meglio"? Sono sempre alla ricerca di modi per migliorare il mio C. In quali circostanze dovrei usare fputsinvece di printf?
Arc676,

10
@ Arc676, per una stringa senza formattazione, fputs è più veloce e più semplice di printf (che deve analizzare la stringa cercando caratteri di formattazione). L'uso di fputs (stdout) piuttosto che solo put () (il cui valore predefinito è stdout) elimina la nuova riga che mette () accoda all'output.
Chad,

45

Non esiste un identificatore di formato per bool. Puoi stamparlo usando alcuni degli identificatori esistenti per la stampa di tipi integrali o fare qualcosa di più fantasioso:

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

Il cast non è necessario.

@ H2CO3 comunque ho suggerito una soluzione di stampa "vero" e "falso" come richiesto da OP. Ho anche leggermente modificato la mia formulazione sulla parte menzionata.
Ivaylo Strandjev,

5
@IvayloStrandjev: Sì, c'è un booltipo in C, non solo nell'edizione C89 - è parte del linguaggio spec C99. C'è una nuova parola chiave _Boole, se includi <stdbool.h>, boolè sinonimo di _Bool.
Adam Rosenfield,

30

ANSI C99 / C11 non include un ulteriore identificatore di conversione printf per bool.

Ma la libreria GNU C fornisce un'API per l'aggiunta di specificatori personalizzati .

Un esempio:

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

Dato che si tratta di estensioni glibc, GCC mette in guardia su tale identificatore personalizzato:

$ gcc -Wall -g main.c -o main
main.c: nella funzione 'main':
main.c: 34: 3: avviso: carattere del tipo di conversione sconosciuto 'B' nel formato [-Wformat =]
   r = printf ("Il risultato è:% B \ n", b);
   ^
main.c: 34: 3: avviso: troppi argomenti per il formato [-Wformat-extra-args]

Produzione:

$ ./main
Il risultato è: falso
(scritto 21 caratteri)
$ ./main 1
Il risultato è: vero
(scritto 20 caratteri)

12

Nella tradizione di itoa():

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

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

5
btoaè "stringa binaria per basare 64 stringhe" in JavaScript non standard (Gecko e WebKit), quindi potresti voler usare un nome diverso.
Panzi,

26
@panzi: non sono sicuro che valga la pena per un programmatore C preoccuparsi di identificatori JavaScript non standard.
Keith Thompson,

5
@KeithThompson Penso di aver confuso le domande e in qualche modo ho pensato che si trattasse di JavaScript, il che non ha comunque senso. Probabilmente era a tarda notte.
Panzi,

9
O, per i più subdoli tra noi: "true\0false"[(!x)*5]:-)
paxdiablo,

1
@MooingDuck: forse !!x*5.
jxh,


2

Se ti piace C ++ meglio di C, puoi provare questo:

#include <ios>
#include <iostream>

bool b = IsSomethingTrue();
std::cout << std::boolalpha << b;

5
Questa risposta è fuori tema e dovrebbe essere eliminata, poiché parla di un'altra lingua rispetto a quella nella domanda.
Lundin,

2
@Lundin Non sono d'accordo sul fatto che questo dovrebbe essere eliminato. L'obiettivo di SO non è solo aiutare una persona, ma aiutare tutte le persone con la stessa domanda. Quando cerco sprintf print booleano come vero falso c ++ , questa è la prima pagina che appare (anche se probabilmente questa pagina potrebbe essere stata il risultato migliore se questa risposta non esistesse). Dato che C ++ è quasi un superset di C, non penso che tali risposte debbano essere scartate così facilmente. +1 da me.
Jeff G

1
@JeffG Sì, tali risposte dovrebbero essere eliminate, abbiamo politiche molto chiare. Leggi i wiki dei tag C e C ++. Questa domanda non è utile per i programmatori C in particolare perché i sistemi booleani C e C ++ sono completamente diversi e la domanda è taggata C. Che Google non sia in grado di comprendere i due ++ in coda nella tua ricerca non è un problema di SO.
Lundin,

2
@Lundin Il mio commento non doveva essere interpretato come un commento sulle politiche di SO. È stato davvero un commento sul fatto che questa risposta si aggiunga in modo costruttivo alla domanda. Questa risposta è immediatamente identificabile come solo C ++. Nessuno venire qui per una sola risposta in C sarebbe indotto a pensare che avrebbe funzionato in C e avrebbe perso tempo a provarlo. Tuttavia, questa è un'ottima risposta per C ++. Se le risposte sono utili, anche se non aiutano l'OP, non dovrebbero essere conservate? Penso che le risposte costruttive che hanno chiaramente identificato avvertimenti non debbano mai essere eliminate, indipendentemente dalla politica.
Jeff G

1
@JeffG Puoi farlo su meta.stackoverflow.com , questo non è il posto dove tenere questa discussione.
Lundin

2

Per stampare solo 1 o 0 in base al valore booleano che ho appena usato:

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

Particolarmente utile con le bandiere:

#define MY_FLAG (1 << 4)
int flags = MY_FLAG;
printf("%d\n", !!(flags & MY_FLAG));

Attenzione che !!potrebbe essere ottimizzato via
ragerdl

1

Preferisco una risposta dal modo migliore per stampare il risultato di un bool come 'falso' o 'vero' in c? , proprio come

printf("%s\n", "false\0true"+6*x);
  • x == 0, "false \ 0true" + 0 "significa" falso ";
  • x == 1, "false \ 0true" + 6 "significa" vero ";

21
Questo è totalmente incomprensibile. Mi ci è voluto molto tempo prima di capire cosa "false\0true"+6*xfacesse davvero. Se lavori in un progetto con altre persone, o semplicemente in un progetto con una base di codice che vuoi capire x anni dopo, le costruzioni come questa devono essere evitate.
Ciao Arrivederci

3
Anche se vedo che questo potrebbe essere più ottimizzato dal momento che è senza filiali. Se la velocità è la tua preoccupazione, questa potrebbe essere un'opzione, assicurati di spiegare bene la meccanica dietro il trucco in un commento. Sarebbe utile anche una funzione inline o una macro con un nome autocompensante (ma probabilmente non sufficiente in questo caso).
Ciao Arrivederci

3
Oltre alle preoccupazioni sulla leggibilità, tieni presente che questo esploderà se qualcuno passa in un valore diverso da 0 o 1.
plugwash

2
@plugwash Potresti ovviamente cambiarlo in printf("%s\n","false\0true"+6*(x?1:0));cui è solo ... il 5% in meno leggibile.
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; } Come con static inline char decimal2char(int d) { assert(d >= 0 && d <= 9); return '0' + d; }; basta avvolgerlo in una funzione con un nome descrittivo e non preoccuparti della sua leggibilità.
yyny,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.