Quel est le spécificateur de format printf pour bool?

458

Depuis ANSI C99 il y a _Boolou boolvia stdbool.h. Mais existe-t-il également un printfspécificateur de format pour bool?

Je veux dire quelque chose comme dans ce pseudo-code:

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

qui imprimerait:

true
maxschlepzig
la source
1
Vous pouvez lire ceci pour plus d'informations cplusplus.com/reference/cstdio/printf Vous pouvez toujours le faire!
Varvarigos Emmanouil
3
@billinkc, ma question n'est pas vraiment de savoir quelle est la meilleure façon d'imprimer des valeurs booléennes - il s'agit d'un spécificateur printf concret. Ce qui ne semble pas exister. Un autre angle pour une bonne réponse serait: peut-être qu'il existe un moyen d'ajouter un spécificateur de format personnalisé à printf qui effectue la conversion
booléenne
Très bien, même si je ne semble pas avoir la possibilité de dévoiler la VtC, je vais donc devoir attendre que mon vote expire.
billinkc
@maxschlepzig: la seule façon de résoudre le problème est de vérifier la documentation. Si vous utilisez GNU / Linux (par exemple, puisque vous ne nous avez pas parlé de votre système), vous pouvez lire un manuel printf à jour sur [Linux man pages] (man7.org). Si vous voulez imprimer des chaînes "true" / "false", vous pouvez les construire manuellement, c'est assez simple.
Bulat M.

Réponses:

711

Il n'y a pas de spécificateur de format pour les booltypes. Cependant, comme tout type intégral plus court que celui intpromu intlorsqu'il est transmis aux printf()arguments variadiques de, vous pouvez utiliser %d:

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

Mais pourquoi pas:

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

ou mieux:

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

ou encore mieux:

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

au lieu?

Adrian Mole
la source
21
Je voudrais +1 si vous vous débarrassez de l'expression littérale non à chaîne unique en tant que chaîne de format. Ce type d'utilisation se transforme facilement en utilisation dangereuse. printf("%s", x ? "true" : "false");résoudrait le problème.
R .. GitHub STOP HELPING ICE
2
Pour la partie «pourquoi pas» de cette réponse - un spécificateur de format pour bool permettrait à la chaîne de format d'être utilisée comme prévu: pour construire une chaîne avec un mélange de littéraux et de valeurs.
noamtm
13
Juste comme une note, j'aurais tendance à contester que printf("%s", x ? "true" : "false");c'est mieux que printf(x ? "true" : "false");- vous avez le contrôle total de la chaîne de format ici, donc il n'y a aucun danger qu'il obtienne quelque chose comme ça "%d"qui causerait des problèmes. Le fputs, d'autre part, est une meilleure option.
paxdiablo
15
Pourquoi est-ce fputs"encore mieux"? Je cherche toujours des moyens d'améliorer mon C. Dans quelles circonstances dois-je utiliser à la fputsplace printf?
Arc676
10
@ Arc676, pour une chaîne sans formatage, fputs est plus rapide et plus simple que printf (qui doit analyser la chaîne à la recherche de caractères de formatage). L'utilisation de fputs (stdout) plutôt que simplement de metts () (qui par défaut est stdout) élimine le retour à la ligne qui ajoute () à la sortie.
Tchad
45

Il n'y a pas de spécificateur de format pour bool. Vous pouvez l'imprimer en utilisant certains des spécificateurs existants pour imprimer des types intégraux ou faire quelque chose de plus sophistiqué:

 printf("%s", x?"true":"false");
Ivaylo Strandjev
la source
Le casting n'est pas nécessaire.
@ H2CO3 de toute façon, j'ai proposé une solution affichant "vrai" et "faux" comme des demandes OP. J'ai également légèrement modifié ma formulation dans la partie que vous mentionnez.
Ivaylo Strandjev
5
@IvayloStrandjev: Oui, il y a un booltype en C, mais pas dans l'édition C89 - cela fait partie des spécifications du langage C99. Il y a un nouveau mot _Bool- clé , et si vous l'incluez <stdbool.h>, alors boolc'est un synonyme pour _Bool.
Adam Rosenfield
30

ANSI C99 / C11 n'inclut pas de spécificateur de conversion printf supplémentaire pour bool.

Mais la bibliothèque GNU C fournit une API pour ajouter des spécificateurs personnalisés .

Un exemple:

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

Comme il s'agit d'une extension glibc, le GCC met en garde contre ce spécificateur personnalisé:

$ gcc -Wall -g main.c -o main
main.c: Dans la fonction 'main':
main.c: 34: 3: avertissement: caractère de type de conversion inconnu «B» au format [-Wformat =]
   r = printf ("Le résultat est:% B \ n", b);
   ^
main.c: 34: 3: avertissement: trop d'arguments pour le format [-Wformat-extra-args]

Production:

$ ./main
Le résultat est: faux
(écrit 21 caractères)
$ ./principal 1
Le résultat est: vrai
(écrit 20 caractères)
maxschlepzig
la source
12

Dans la tradition de itoa():

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

bool x = true;
printf("%s\n", btoa(x));
jxh
la source
5
btoaest "chaîne binaire à chaîne de base 64" en JavaScript non standard (Gecko et WebKit), vous pouvez donc utiliser un nom différent.
panzi
26
@panzi: Je ne suis pas sûr que cela vaille la peine qu'un programmeur C s'inquiète des identifiants JavaScript non standard.
Keith Thompson
5
@KeithThompson Je pense que j'ai confondu les questions et que je pensais que c'était à propos de JavaScript, ce qui n'a aucun sens de toute façon. Il était probablement tard dans la nuit.
panzi
9
Ou, pour les plus sournois d'entre nous: "true\0false"[(!x)*5]:-)
paxdiablo
1
@MooingDuck: peut-être !!x*5.
jxh
4

Vous ne pouvez pas, mais vous pouvez imprimer 0 ou 1

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

la source

Stephan
la source
2

Si vous aimez mieux C ++ que C, vous pouvez essayer ceci:

#include <ios>
#include <iostream>

bool b = IsSomethingTrue();
std::cout << std::boolalpha << b;
Arsen YM
la source
5
Cette réponse est hors sujet et doit être supprimée, car il s'agit d'une autre langue que celle de la question.
Lundin
2
@Lundin Je ne suis pas d'accord pour que cela soit supprimé. L'objectif de SO n'est pas seulement d'aider une seule personne, mais d'aider toutes les personnes ayant la même question. Lorsque je recherche le sprintf print boolean comme true false c ++ , c'est la première page qui apparaît (bien que sans doute cette page ait pu être le meilleur résultat si cette réponse n'existait pas). Étant donné que C ++ est presque un surensemble de C, je ne pense pas que de telles réponses devraient être si facilement rejetées. +1 de moi.
Jeff G
1
@JeffG Oui, ces réponses doivent être supprimées, nous avons des politiques très claires. Lisez les wikis des balises C et C ++. Cette question n'est pas utile aux programmeurs C, en particulier parce que les systèmes booléens C et C ++ sont entièrement différents et la question est étiquetée C. Que Google ne soit pas en mesure de comprendre les deux ++ derrière dans votre recherche n'est pas le problème de SO.
Lundin
2
@Lundin Mon commentaire n'était pas destiné à être interprété comme un commentaire sur les politiques de SO. C'était vraiment un commentaire pour savoir si cette réponse ajoute de manière constructive à la question. Cette réponse est immédiatement identifiable en C ++ uniquement. Personne ne venant ici pour une réponse en C uniquement serait trompé en pensant que cela fonctionnerait en C et perdrait du temps à essayer. Cependant, c'est une excellente réponse pour C ++. Si les réponses sont utiles, même si elles n'aident pas le PO, ne devraient-elles pas être conservées? Je pense que les réponses constructives qui ont clairement identifié des mises en garde ne devraient jamais être supprimées, quelle que soit la politique.
Jeff G
1
@JeffG Vous pouvez en parler sur meta.stackoverflow.com , ce n'est pas l'endroit pour avoir cette discussion.
Lundin
2

Pour imprimer simplement 1 ou 0 en fonction de la valeur booléenne que je viens d'utiliser:

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

Particulièrement utile avec les drapeaux:

#define MY_FLAG (1 << 4)
int flags = MY_FLAG;
printf("%d\n", !!(flags & MY_FLAG));
Tarion
la source
Méfiez-vous que le !!pourrait être optimisé
ragerdl
1

Je préfère une réponse de Best way pour imprimer le résultat d'un booléen comme «faux» ou «vrai» en c? , juste comme

printf("%s\n", "false\0true"+6*x);
  • x == 0, "false \ 0true" + 0 "cela signifie" false ";
  • x == 1, "false \ 0true" + 6 "cela signifie" vrai ";
xjzhou
la source
21
C'est totalement incompréhensible. Il m'a fallu un bon moment avant de comprendre ce "false\0true"+6*xqui s'est réellement passé. Si vous travaillez dans un projet avec d'autres personnes, ou simplement dans un projet avec une base de code que vous souhaitez comprendre x ans plus tard, des constructions comme celle-ci doivent être évitées.
HelloGoodbye
3
Bien que je vois que cela pourrait être plus optimisé car il est sans branche. Si la vitesse est votre préoccupation, cela pourrait être une option, assurez-vous d'expliquer bien les mécanismes derrière l'astuce dans un commentaire. Une fonction ou une macro en ligne avec un nom auto-documenté serait également utile (mais probablement pas suffisante dans ce cas).
HelloGoodbye
3
En plus des inquiétudes concernant la lisibilité, gardez à l'esprit que cela explosera si quelqu'un passe une valeur autre que 0 ou 1.
plugwash
2
@plugwash Vous pouvez bien sûr le changer, ce printf("%s\n","false\0true"+6*(x?1:0));qui n'est que ... 5% moins lisible.
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; } Identique à static inline char decimal2char(int d) { assert(d >= 0 && d <= 9); return '0' + d; }; il suffit de l'envelopper dans une fonction nommée de manière descriptive et ne vous inquiétez pas de sa lisibilité.
yyny