Что такое спецификатор формата printf для bool?

458

С ANSI C99 есть _Boolили boolчерез stdbool.h. Но есть ли printfспецификатор формата для bool?

Я имею в виду что-то вроде этого псевдокода:

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

который напечатал бы:

true
maxschlepzig
источник
1
Вы можете прочитать это для получения дополнительной информации cplusplus.com/reference/cstdio/printf Вы всегда можете сделать это, хотя!
Варваригос Эммануил
3
@billinkc, мой вопрос на самом деле не о том, как лучше всего печатать значения bool, а о конкретном спецификаторе printf. Которого, кажется, не существует. Другим углом к ​​хорошему ответу было бы: возможно, есть способ добавить пользовательский спецификатор формата в printf, который выполняет преобразование bool ...
maxschlepzig
Справедливо, хотя у меня, похоже, нет возможности распечатать VtC, поэтому мне просто нужно подождать, пока истечет срок моего голосования.
billinkc
@maxschlepzig: единственный способ решить проблему - проверить документацию. Если вы используете GNU / Linux (например, поскольку вы не сообщили нам о своей системе), вы можете прочитать новейшее руководство по printf на [страницах man Linux] (man7.org). Если вы хотите напечатать «истинные» / «ложные» строки, вы можете создать их вручную, это довольно просто.
Булат М.

Ответы:

711

Для boolтипов нет спецификатора формата . Тем не менее, поскольку любой целочисленный тип короче, чем intпродвигается intпри printf()передаче аргументов с переменным аргументом, вы можете использовать %d:

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

Но почему нет:

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

или лучше:

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

или даже лучше:

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

вместо?

Адриан Моул
источник
21
Я бы добавил +1, если вы избавитесь от выражения, не являющегося строковым литералом, в качестве строки формата. Этот вид использования легко превращается в небезопасное использование. printf("%s", x ? "true" : "false");бы решить проблему.
R .. GitHub ОСТАНОВИТЬ ЛЬДА
2
Для части «почему нет» этого ответа - спецификатор формата для bool позволил бы использовать форматную строку, как задумано: для создания строки со смесью литералов и значений.
noamtm
13
Как примечание, я склонен оспаривать это printf("%s", x ? "true" : "false"); это лучше , что printf(x ? "true" : "false");вы - в общем контроле строки формата здесь , поэтому нет нет опасности , что он будет получать что - то подобное , "%d"которое вызвало бы проблемы. fputs, С другой стороны, это лучший вариант.
paxdiablo
15
Почему fputs"еще лучше"? Я всегда ищу способы улучшить мой C. При каких обстоятельствах я должен использовать fputsвместо printf?
Arc676
10
@ Arc676, для строки без форматирования fputs быстрее и проще, чем printf (который должен анализировать строку в поисках символов форматирования). Использование fputs (stdout) вместо просто put () (по умолчанию это stdout) исключает символ новой строки, который приставляет () к выводу.
Чад
45

Для bool нет спецификатора формата. Вы можете распечатать его, используя некоторые из существующих спецификаторов для печати целочисленных типов или сделать что-то более причудливое:

 printf("%s", x?"true":"false");
Ивайло Странджев
источник
Актерский состав не нужен.
@ H2CO3 В любом случае я предложил решение, печатающее «true» и «false» в качестве запросов OP. Я также немного изменил свою формулировку в части, которую вы упоминаете.
Ивайло Странджев
5
@IvayloStrandjev: Да, там естьbool типа в C, но только не в C89 издание - это часть языка спецификации C99. Есть новое ключевое слово _Bool, и если вы включите <stdbool.h>, то boolэто синоним для _Bool.
Адам Розенфилд
30

ANSI C99 / C11 не включает дополнительный спецификатор преобразования printf для bool .

Но библиотека GNU C предоставляет API для добавления пользовательских спецификаторов .

Пример:

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

Поскольку это расширение glibc, GCC предупреждает об этом пользовательском спецификаторе:

$ gcc -Wall -g main.c -o main
main.c: в функции 'main':
main.c: 34: 3: предупреждение: неизвестный символ типа преобразования "B" в формате [-Wformat =]
   r = printf («Результат:% B \ n», b);
   ^
main.c: 34: 3: предупреждение: слишком много аргументов для формата [-Wformat-extra-args]

Вывод:

$ ./main
Результат: ложь
(написано 21 символов)
$ ./main 1
Результат: правда
(написано 20 символов)
maxschlepzig
источник
12

В традиции itoa():

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

bool x = true;
printf("%s\n", btoa(x));
jxh
источник
5
btoaявляется «строкой двоичной строки в базе 64» в нестандартном JavaScript (Gecko и WebKit), поэтому вы можете использовать другое имя.
Panzi
26
@panzi: Я не уверен, что программисту Си стоит потрудиться беспокоиться о нестандартных идентификаторах JavaScript.
Кит Томпсон
5
@KeithThompson Я думаю, что перепутал вопросы и почему-то подумал, что речь идет о JavaScript, что в любом случае не имеет смысла. Это было, вероятно, поздно ночью.
Panzi
9
Или, для более коварных среди нас: "true\0false"[(!x)*5]:-)
paxdiablo
1
@MooingDuck: возможно !!x*5.
JXH
2

Если вам нравится C ++ лучше, чем C, вы можете попробовать это:

#include <ios>
#include <iostream>

bool b = IsSomethingTrue();
std::cout << std::boolalpha << b;
Арсен Ю.М.
источник
5
Этот ответ не по теме и должен быть удален, поскольку речь идет о другом языке, чем тот, который указан в вопросе.
Лундин
2
@Lundin Я не согласен, что это должно быть удалено. Цель SO - не просто помочь одному человеку, но помочь всем людям с одним и тем же вопросом. Когда я ищу sprintf print boolean как true false c ++ , это первая страница, которая появляется (хотя, возможно, эта страница могла быть лучшим результатом, если этот ответ не существовал). Поскольку C ++ является почти надмножеством C, я не думаю, что такие ответы следует так легко отбрасывать. +1 от меня.
Джефф Г
1
@JeffG Да, такие ответы должны быть удалены, у нас очень четкие правила. Прочитайте вики-теги C и C ++. Этот вопрос бесполезен для программистов на C, особенно потому, что булевы системы C и C ++ совершенно разные и вопрос помечен как C. То, что Google не может понять два конечных ++ в вашем поиске, не является проблемой SO.
Лундин
2
@Lundin Мой комментарий не должен быть истолкован как комментарий к политике SO. Это был действительно комментарий о том, добавляет ли этот ответ конструктивно к вопросу. Этот ответ сразу идентифицируется как только C ++. Никто не придет сюда за ответом только на C, и его не будут обманывать, если он будет думать, что это сработает на C, и тратит время на его попытки. Тем не менее, это отличный ответ для C ++. Если ответы полезны, даже если они не помогают ФП, их не следует хранить? Я думаю, что конструктивные ответы, в которых четко определены предостережения, никогда не следует удалять, независимо от политики.
Джефф Г
1
@JeffG Вы можете поднять это на meta.stackoverflow.com , здесь не место для этого обсуждения.
Лундин
2

Чтобы просто напечатать 1 или 0 на основе логического значения, которое я только что использовал:

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

Особенно полезно с флагами:

#define MY_FLAG (1 << 4)
int flags = MY_FLAG;
printf("%d\n", !!(flags & MY_FLAG));
Тарион
источник
Остерегайтесь, что это !!может быть оптимизировано
ragerdl
1

Я предпочитаю ответ из Best way, чтобы напечатать результат bool как «false» или «true» в c? , как

printf("%s\n", "false\0true"+6*x);
  • x == 0, "false \ 0true" + 0 "это означает" false ";
  • x == 1, "false \ 0true" + 6 "означает" true ";
xjzhou
источник
21
Это совершенно непостижимо. Мне потребовалось некоторое время, прежде чем я понял, что на "false\0true"+6*xсамом деле. Если вы работаете в проекте с другими людьми или просто в проекте с базой кода, которую вы хотите понять спустя x лет, таких конструкций следует избегать.
Здравствуйте, до свидания,
3
Хотя я вижу, что это может быть более оптимизировано, поскольку оно не требует ответвлений. Если вам важна скорость, это может быть вариантом, просто обязательно объясните механику, стоящую за этим трюком, в комментарии. Встроенная функция или макрос с самодокументируемым именем также были бы полезны (но, вероятно, не достаточны в этом случае).
Привет, до свидания,
3
Так же как и проблемы с читабельностью, имейте в виду, что это взорвется, если кто-то передаст значение, отличное от 0 или 1.
plugwash
2
@plugwash Конечно, вы можете изменить его на printf("%s\n","false\0true"+6*(x?1:0));... только на 5% менее читабельный.
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; } То же, что и с static inline char decimal2char(int d) { assert(d >= 0 && d <= 9); return '0' + d; }; просто оберните его в описательно названную функцию и не беспокойтесь о его удобочитаемости.
yyny