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


458

Оскільки ANSI C99 є _Boolабо boolчерез stdbool.h. Але чи є також printfспецифікатор формату для bool?

Я маю на увазі щось на кшталт цього псевдокоду:

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

що друкувало б:

true

1
Ви можете прочитати це для отримання додаткової інформації cplusplus.com/reference/cstdio/printf Ви завжди можете це зробити!
Варварігос Еммануїл


3
@billinkc, моє запитання насправді не в тому, який найкращий спосіб друкувати значення bool - це про конкретний специфікатор printf. Яка, здається, не існує. Ще один кут приємної відповіді буде: можливо, є спосіб додати спеціальний специфікатор формату до printf, який робить перетворення bool ...
maxschlepzig

Досить справедливо, хоча, здається, я не маю можливості розголошувати VtC, тому мені доведеться просто почекати закінчення мого голосу.
billinkc

@maxschlepzig: єдиний спосіб вирішити проблему - перевірити документацію. Якщо ви використовуєте GNU / Linux (наприклад, оскільки ви не повідомили нам про вашу систему), ви можете прочитати оновлений посібник щодо printf на [Linux man pages] (man7.org). Якщо ви хочете, щоб надруковані "true" / "false" рядки були складені вручну, це досить просто.
Булат М.

Відповіді:


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) виключає новий рядок, який put () додає до виводу.
Чад

45

Не існує специфікатора формату для bool. Ви можете роздрукувати його за допомогою деяких існуючих специфікаторів для друку інтегральних типів або зробити щось більш фантазійне:

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

Акторський склад не потрібен.

@ H2CO3 у будь-якому разі я запропонував роздрукувати рішення "true" та "false" як запити ОП. Я також трохи змінив своє формулювання з тієї частини, яку ви згадуєте.
Івайло Страндєв

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 -о головний
main.c: У функції 'main':
main.c: 34: 3: попередження: невідомий символ типу конверсії "B" у форматі [-Wformat =]
   r = printf ("Результат:% B \ n", b);
   ^
main.c: 34: 3: попередження: занадто багато аргументів для формату [-Wformat-extra-args]

Вихід:

$ ./ головна
Результат: хибний
(написано 21 символ)
$ ./ головна 1
Результат: правда
(написано 20 символів)

12

У традиції itoa():

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

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

5
btoaє "бінарний рядок до бази 64 рядка" в нестандартному JavaScript (Gecko та WebKit), тому ви, можливо, захочете використовувати інше ім'я.
panzi

26
@panzi: Я не впевнений, що C програмісту варто докладати зусиль, щоб переживати про нестандартні ідентифікатори JavaScript.
Кіт Томпсон

5
@KeithThompson Я думаю, що я переплутав питання і якось подумав, що це стосується JavaScript, але це ніяк не має сенсу. Напевно, було пізно вночі.
панци

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 Я не погоджуюся з тим, що це слід видалити. Мета ТА не просто допомогти одній людині, а допомогти всім людям з одним і тим же питанням. Коли я шукаю буферу sprintf print boole як справжню помилкову c ++ , це перша сторінка, що з’являється (хоча, мабуть, ця сторінка була найкращим результатом, якщо такої відповіді не було). Оскільки C ++ є майже сукупністю C, я не думаю, що такі відповіді не можна так легко відкинути. +1 від мене.
Jeff G

1
@JeffG Так, такі відповіді потрібно видалити, у нас дуже чітка політика. Прочитайте вікі із тегами C та C ++. Це питання не допомагає програмістам на C, особливо тому, що булева система C і C ++ абсолютно інша, а питання позначено C. Що Google не в змозі зрозуміти два знаки ++ у вашому пошуку, це не проблема.
Лундін

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

Я вважаю за краще відповідь від Найкращий спосіб надрукувати результат bool як "false" або "true" в c? , так як

printf("%s\n", "false\0true"+6*x);
  • x == 0, "false \ 0true" + 0 "це означає" false ";
  • x == 1, "false \ 0true" + 6 "це означає" вірно ";

21
Це абсолютно незрозуміло. Це зайняло мене непогано, перш ніж я зрозумів, що "false\0true"+6*xнасправді зробив. Якщо ви працюєте в проекті з іншими людьми або просто в проекті з кодовою базою, яку ви хочете зрозуміти через x років, подібних конструкцій слід уникати.
HelloGoodbye

3
Хоча я бачу, що це може бути оптимізованіше, оскільки воно не має гілок. Якщо швидкість викликає занепокоєння, це може бути варіантом, просто переконайтесь, що в коментарі добре поясніть механіку, що стоїть за трюком. Вбудована функція або макрос із назвою самодокументування також буде корисною (але, мабуть, недостатньою у цьому випадку).
HelloGoodbye

3
Також, як і занепокоєння з приводу читабельності, майте на увазі, що це вибухне, якщо хтось перейде у значення, відмінне від 0 або 1.
Підключіть

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.