Jaki jest specyfikator formatu printf dla bool?

457

Od ANSI C99 jest _Boollub boolprzez stdbool.h. Ale czy istnieje również printfspecyfikator formatu dla bool?

Mam na myśli coś takiego w tym pseudo kodzie:

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

który wydrukowałby:

true
maxschlepzig
źródło
1
Możesz przeczytać to w celu uzyskania dalszych informacji cplusplus.com/reference/cstdio/printf Zawsze możesz to zrobić!
Varvarigos Emmanouil
3
@billinkc, moje pytanie tak naprawdę nie dotyczy tego, jak najlepiej wydrukować wartości bool - chodzi o konkretny specyfikator printf. Który wydaje się nie istnieć. Innym kątem do ładnej odpowiedzi byłoby: być może istnieje sposób, aby dodać specyfikator formatu niestandardowego do printf, który dokonuje konwersji bool ...
maxschlepzig
W porządku, chociaż wydaje mi się, że nie jestem w stanie wyemitować VtC, więc będę musiał poczekać na wygaśnięcie mojego głosu.
billinkc
@maxschlepzig: jedynym sposobem rozwiązania problemu jest sprawdzenie dokumentacji. Jeśli używasz GNU / Linux (jako przykład, ponieważ nie powiedziałeś nam o swoim systemie), możesz przeczytać aktualną instrukcję printf na [stronach Linuxa] (man7.org). Jeśli chcesz wydrukować ciągi „prawda” / „fałsz”, możesz je zbudować ręcznie, jest to dość łatwe.
Bulat M.

Odpowiedzi:

709

Nie ma specyfikatora formatu dla booltypów. Ponieważ jednak dowolny typ całkowy krótszy niż intpromowany, intgdy jest przekazywany do printf()argumentów variadic, możesz użyć %d:

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

Ale dlaczego nie:

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

albo lepiej:

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

lub nawet lepiej:

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

zamiast?

Adrian Mole
źródło
21
Dałbym +1, jeśli pozbyłbyś się wyrażenia nie będącego jednym ciągiem literalnym jako ciągu formatu. Ten rodzaj użytkowania łatwo przekształca się w niebezpieczne użycie. printf("%s", x ? "true" : "false");rozwiązałoby problem.
R .. GitHub PRZESTAŃ POMÓC LODOWI
2
W części „dlaczego nie” tej odpowiedzi - specyfikator formatu dla bool pozwoliłby na użycie łańcucha formatu zgodnie z przeznaczeniem: do konstruowania łańcucha z mieszanką literałów i wartości.
noamtm
13
Podobnie jak notatki, to bym raczej ku kwestionując, że printf("%s", x ? "true" : "false");jest lepiej , że printf(x ? "true" : "false");- jesteś w całkowitej kontroli ciągu formatu tutaj więc nie ma żadnego niebezpieczeństwa, że będzie to coś jak "%d"które mogłyby powodować problemy. Z fputsdrugiej strony jest lepszym rozwiązaniem.
paxdiablo
15
Dlaczego fputs„jeszcze lepiej”? Zawsze szukam sposobów na poprawę mojego C. W jakich okolicznościach powinienem stosować fputszamiast printf?
Arc676,
10
@ Arc676, dla łańcucha bez formatowania, fputs jest szybszy i prostszy niż printf (który musi parsować ciąg szukając znaków formatujących). Użycie fputs (stdout) zamiast po prostu puts () (domyślnie stdout) eliminuje nowy wiersz, który puts () dołącza do wyniku.
Czad
45

Nie ma specyfikatora formatu dla bool. Możesz wydrukować go za pomocą niektórych istniejących specyfikatorów do drukowania typów całkowitych lub zrobić coś bardziej wymyślnego:

 printf("%s", x?"true":"false");
Ivaylo Strandjev
źródło
Obsada nie jest potrzebna.
@ H2CO3 w każdym razie zasugerowałem rozwiązanie drukujące „prawda” i „fałsz” jako żądania OP. Zmieniłem też nieznacznie moje sformułowanie w części, o której wspomniałeś.
Ivaylo Strandjev
5
@IvayloStrandjev: Tak, tam jestbool typ w C, nie tylko w wersji C89 - to część języka specyfikacji C99. Pojawiło się nowe słowo kluczowe _Bool, a jeśli je podasz <stdbool.h>, boolto synonim _Bool.
Adam Rosenfield,
30

ANSI C99 / C11 nie zawierają dodatkowego specyfikatora konwersji printf dla bool.

Ale biblioteka GNU C zapewnia interfejs API do dodawania niestandardowych specyfikatorów .

Przykład:

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

Ponieważ jest to rozszerzenie glibc, GCC ostrzega przed tym niestandardowym specyfikatorem:

$ gcc -Wall -g main.c -o main
main.c: W funkcji „main”:
main.c: 34: 3: ostrzeżenie: nieznany typ konwersji znak „B” w formacie [-Wformat =]
   r = printf („Wynikiem jest:% B \ n”, b);
   ^
main.c: 34: 3: ostrzeżenie: zbyt wiele argumentów dla formatu [-Wformat-extra-args]

Wynik:

$ ./main
Wynik jest następujący: false
(napisane 21 znaków)
$ ./main 1
Wynik jest następujący: prawda
(napisano 20 znaków)
maxschlepzig
źródło
12

W tradycji itoa():

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

bool x = true;
printf("%s\n", btoa(x));
jxh
źródło
5
btoato „ciąg binarny do podstawowego ciągu 64” w niestandardowym JavaScript (Gecko i WebKit), więc możesz chcieć użyć innej nazwy.
panzi
26
@panzi: Nie jestem pewien, czy programista C powinien się martwić o niestandardowe identyfikatory JavaScript.
Keith Thompson
5
@KeithThompson Myślę, że pomyliłem pytania i jakoś pomyślałem, że chodzi o JavaScript, co i tak nie ma sensu. Prawdopodobnie było późno w nocy.
panzi
9
Lub, dla bardziej przebiegłych wśród nas: "true\0false"[(!x)*5]:-)
paxdiablo
1
@MooingDuck: może !!x*5.
jxh
4

Nie możesz, ale możesz wydrukować 0 lub 1

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

źródło

Stephan
źródło
2

Jeśli podoba Ci się C ++ lepiej niż C, możesz spróbować:

#include <ios>
#include <iostream>

bool b = IsSomethingTrue();
std::cout << std::boolalpha << b;
Arsen YM
źródło
5
Ta odpowiedź jest nie na temat i powinna zostać usunięta, ponieważ dotyczy innego języka niż ten w pytaniu.
Lundin
2
@Lundin Nie zgadzam się, że należy to usunąć. Celem SO jest nie tylko pomoc jednej osobie, ale także pomoc wszystkim ludziom z tym samym pytaniem. Kiedy szukam booleanu sprintf print jako true false C ++ , pojawia się pierwsza strona (choć zapewne ta strona może być najlepszym wynikiem, jeśli ta odpowiedź nie istnieje). Ponieważ C ++ jest prawie nadzbiorem C, nie sądzę, że takie odpowiedzi powinny być tak łatwo odrzucane. +1 ode mnie
Jeff G
1
@JeffG Tak, takie odpowiedzi należy usunąć, mamy bardzo jasne zasady. Przeczytaj strony wiki z tagami C i C ++. To pytanie nie jest pomocne dla programistów C, szczególnie dlatego, że systemy logiczne C i C ++ są zupełnie inne, a pytanie jest oznaczone jako C. To, że Google nie jest w stanie zrozumieć dwóch końcowych ++ w twoim wyszukiwaniu, nie jest problemem SO.
Lundin,
2
@Lundin Mój komentarz nie miał być interpretowany jako komentarz do zasad SO. To był naprawdę komentarz, czy ta odpowiedź konstruktywnie dodaje pytanie. Ta odpowiedź jest natychmiast identyfikowalna jako tylko C ++. Nikt nie przychodzi tutaj po odpowiedź tylko w języku C, aby pomyśleć, że zadziała to w C i zmarnuje czas na próby. Jest to jednak świetna odpowiedź dla C ++. Jeśli odpowiedzi są przydatne, nawet jeśli nie pomagają OP, to czy nie powinny być przechowywane? Myślę, że konstruktywne odpowiedzi, które jasno wskazują zastrzeżenia, nigdy nie powinny być usuwane, niezależnie od zasad.
Jeff G
1
@JeffG Możesz poruszaćkwestię na stronie meta.stackoverflow.com , nie jest to miejsce na tę dyskusję.
Lundin,
2

Aby po prostu wydrukować 1 lub 0 na podstawie właśnie użytej wartości logicznej:

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

Szczególnie przydatne z flagami:

#define MY_FLAG (1 << 4)
int flags = MY_FLAG;
printf("%d\n", !!(flags & MY_FLAG));
Tarion
źródło
Uważaj, że !!może zostać zoptymalizowany
ragerdl
1

Wolę odpowiedź od najlepszego sposobu, aby wydrukować wynik bool jako „fałsz” lub „prawda” w c? , tak jak

printf("%s\n", "false\0true"+6*x);
  • x == 0, „false \ 0true” + 0 ”oznacza„ false ”;
  • x == 1, „false \ 0true” + 6 ”oznacza„ prawda ”;
Xjzhou
źródło
21
To jest całkowicie niezrozumiałe. Zajęło mi "false\0true"+6*xsporo czasu, zanim zorientowałem się, co naprawdę zrobiłem. Jeśli pracujesz w projekcie z innymi ludźmi lub po prostu w projekcie z bazą kodu, którą chcesz zrozumieć x lata później, należy unikać takich konstrukcji.
HelloGoodbye
3
Chociaż widzę, że może to być bardziej zoptymalizowane, ponieważ nie ma gałęzi. Jeśli zależy Ci na prędkości, może to być opcja, po prostu dobrze wyjaśnij mechanikę sztuczki w komentarzu. Przydałaby się również funkcja wbudowana lub makro z nazwą samodokumentującą (ale prawdopodobnie w tym przypadku niewystarczające).
HelloGoodbye
3
Oprócz obaw związanych z czytelnością należy pamiętać, że
wybuchnie,
2
@plugwash Możesz oczywiście zmienić na, printf("%s\n","false\0true"+6*(x?1:0));który jest tylko ... 5% mniej czytelny.
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; } Taki sam jak z static inline char decimal2char(int d) { assert(d >= 0 && d <= 9); return '0' + d; }; po prostu zawiń ją w funkcję o nazwie opisowej i nie martw się o jej czytelność.
yyny