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.