布尔类型的printf格式说明符是什么?

685
自从ANSI C99之后,通过`stdbool.h`头文件可以使用`_Bool`或`bool`类型。但是是否也有针对布尔值的`printf`格式说明符呢?
我的意思是类似于下面这条伪代码:
bool x = true;
printf("%B\n", x);

这将打印出:

true

2
你可以阅读此链接以获取更多信息:http://www.cplusplus.com/reference/cstdio/printf/ 不过你总是可以做到的! - Varvarigos Emmanouil
5
@billinkc,我的问题实际上不是关于打印布尔值的最佳方法是什么 - 它关于一个具体的printf格式说明符。然而这个格式说明符似乎并不存在。另一个好答案的角度可能是:也许有一种方法可以添加自定义的格式说明符到printf中来进行布尔转换... - maxschlepzig
1
好的,虽然我似乎没有取消 VtC 的能力,所以我只能等待我的投票过期。 - billinkc
1
@maxschlepzig:解决问题的唯一方法是查看文档。如果您使用GNU/Linux(例如,因为您没有告诉我们您的系统),您可以在Linux man pages上阅读最新的printf手册。如果您想要打印“true”/“false”字符串,您可以手动构造它们,这很容易。 - anon
8个回答

1052

对于 bool 类型,没有格式说明符。但是,由于任何比 int 更短的整数类型在传递给 printf() 的可变参数时都会被提升为 int,因此您可以使用 %d

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

但为什么不呢:

printf("Your boolean variable is: %s", x ? "true" : "false");

改用什么?


31
如果您将非单字符串文字表达式作为格式字符串排除,我会点赞此操作。这种用法很容易变成不安全的用法。printf("%s", x ? "true" : "false"); 会解决这个问题。 - R.. GitHub STOP HELPING ICE
26
注意,我倾向于争辩说 printf("%s", x ? "true" : "false"); 不比 printf(x ? "true" : "false"); 更好 - 在这里你完全控制格式字符串,所以没有任何危险会出现像 "%d" 这样会导致问题的情况。另一方面,使用 fputs 是更好的选择。 - paxdiablo
6
将单个char *传递给printf()被视为不良实践,因为这实际上应该是一个格式字符串。未转义的百分号可能会导致程序崩溃(更多信息请参见此处)。 因此,printf("%s",...)更安全。 如果您一开始没有进行任何实际格式化,那么printf函数族就过度了,使用puts()(或者如果需要打印到stderr,则使用fputs())更加高效/简洁。 - sevko
23
为什么fputs更好?我一直在寻找提高C语言的方法。在什么情况下,我应该使用fputs而不是printf - Arc676
19
对于没有格式的字符串来说,fputs比printf更快更简单(因为printf需要解析字符串以查找格式字符)。使用fputs(stdout)而不是只用puts()(默认输出到stdout)可以消除puts()在输出末尾添加的换行符。 - Chad
显示剩余7条评论

75

没有适用于bool的格式说明符。您可以使用一些现有的打印整数类型的说明符来打印它,或者进行更花哨的处理:

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

1
@H2CO3 不管怎样,我已经建议一个解决方案,按照 OP 的要求打印“true”和“false”。在你提到的部分,我也稍微改变了措辞。 - Ivaylo Strandjev
6
在C语言中确实有bool类型,但是在C89版规范中没有 -- 它是C99语言规范的一部分。现在有一个新的关键字_Bool,如果你包含了<stdbool.h>头文件,那么bool就是_Bool的一个同义词。 - Adam Rosenfield

41

ANSI C99/C11没有为bool类型提供额外的printf转换说明符。

但是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: In function ‘main’:
main.c:34:3: warning: unknown conversion type character ‘B’ in format [-Wformat=]
   r = printf("The result is: %B\n", b);
   ^
main.c:34:3: warning: too many arguments for format [-Wformat-extra-args]

输出:

$ ./main
结果为:false
(共写入21个字符)
$ ./main 1
结果为:true
(共写入20个字符)

15

遵循itoa()的传统:

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

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

5
"btoa" 是非标准的 JavaScript(Gecko 和 WebKit)中的“二进制字符串到 base64 字符串”函数,因此你可能需要使用其他名称。 - panzi
41
@panzi: 我不确定一位C程序员费心去关注非标准的JavaScript标识符是否值得。 - Keith Thompson
5
我觉得我混淆了问题,不知怎么想到这是关于JavaScript的,其实这毫无意义。可能当时已经很晚了。 - panzi
13
对于我们中的更狡猾者可以这样做:"true\0false"[(!x)*5] :-) (注:此代码片段的作用是根据变量x的真假返回字符串"true"或"false") - paxdiablo
1
@MooingDuck: 也许可以尝试 !!x*5 - jxh
显示剩余5条评论

5
你无法这样做,但是你可以打印0或1。
_Bool b = 1;
printf("%d\n", b);

source


3

如果我只想根据布尔值打印1或0:

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

特别适用于标志:

#define MY_FLAG (1 << 4)
int flags = MY_FLAG;
printf("%d\n", !!(flags & MY_FLAG));

1
请注意,!! 可能会被优化掉。 - interestedparty333
1
如果MY_FLAG等于1,则!!(flags&MY_FLAG)可以被替换为(flags&MY_FLAG),但是非损坏的编译器除非能够证明操作数不能有任何值而不是0或1,否则无法优化掉!! - supercat

2

如果您比较喜欢C++而不是C语言,您可以尝试以下方法:

#include <ios>
#include <iostream>

bool b = IsSomethingTrue();
std::cout << std::boolalpha << b;

9
此回答与问题所涉及的语言不一致,属于离题内容应予删除。 - Lundin
6
我不同意应该删除这个回答。SO的目标不仅是帮助一个人,而是帮助所有有相同问题的人。当我搜索sprintf print boolean as true false c++时,这是第一页出现的结果(尽管如果这个回答不存在,这个页面可能会成为最高排名的结果)。由于C++几乎是C的超集,我认为不应该轻易地抛弃这样的答案。我的投票+1。 - Jeff G
2
是的,这样的答案应该被删除,我们有非常明确的政策。阅读C和C++标签维基页面。对于C程序员来说,这个问题并不有帮助,特别是因为C和C++的布尔系统完全不同,并且这个问题被标记为C。谷歌无法理解您搜索中的两个尾随++不是SO的问题。 - Lundin
3
我的评论并不是针对SO的政策。它实际上是关于这个答案是否对问题有建设性的评论。这个答案很容易被识别为仅适用于C++。没有人会因此误以为在C中也可以工作,并浪费时间尝试。然而,对于C++来说,这是一个很好的答案。如果答案有用,即使它们对OP没有帮助,它们也应该保留吗?我认为,只要有明确定义的警告,有建设性的答案就不应该被删除,而与政策无关。 - Jeff G
3
@JeffG 你可以在 https://meta.stackoverflow.com 上提出这个问题,这里不是讨论的地方。 - Lundin

-1

30
这段话的意思是:这完全难以理解。我花费了很长时间才弄清楚"false\0true"+6*x实际上是什么意思。如果你在与其他人合作的项目中工作,或者只是在一个你想要在_x_年后理解代码库的项目中工作,应该避免使用这样的结构。 - HelloGoodbye
3
尽管我发现这种方法可能更优化,因为它没有分支。如果速度是您关注的问题,这可能是一个选项,只需确保在注释中很好地解释这个技巧的机制。一个具有自说明名称的内联函数或宏也会有所帮助(但在这种情况下可能不足够)。 - HelloGoodbye
4
请注意阅读易懂性的问题,同时要记住,如果有人传入除0或1以外的值,这将会出问题。 - plugwash
2
@plugwash 当然,你可以将其更改为 printf("%s\n","false\0true"+6*(x?1:0));,这只会少了5%的可读性。 - Alex Shroyer
2
这个解决方案的另一个问题是,如果用于外语中,数字6就必须更改。例如,如果x为true,则"ложь\0истина" + 6*x将打印出“ь”,即俄语单词false的最后一个字母,因为在UTF-8编码中该单词占用8个字节而不是5个字节。数字6必须更改为9。 - Thomas Hedden
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接