_Bool 的 'printf' 转换说明符存在吗?

14

使用printf(),我可以使用%hhu来表示unsigned char%hi来表示short int%zu来表示size_t%tx来表示ptrdiff_t等等。

对于_Bool类型,我应该使用哪种转换格式说明符?标准中是否存在这样的说明符?

还是我需要像这样进行强制类型转换:

_Bool foo = 1;
printf("foo: %i\n", (int)foo);

1
我认为在 foo 前面不需要强制转换:_Bool 默认会被转换为 int - Sergey Kalinichenko
2
如果我没记错的话,默认提升规则总是适用于变长参数:float 变成 double,char 变成 int,等等。这在 C99 中可能已经有所改变,我不确定。 - Sergey Kalinichenko
1
@Jack:我持怀疑态度——需要引用。 :) C99 6.3.1.1p1说,_Bool的转换等级低于所有其他标准整数类型的等级,如果它是typedefed(对吧?)就不可能是真的。此外,6.3.1.2描述了_Bool的特殊转换规则,如果_Bool只是typedefed为int,则无法工作。 - Richard Hansen
3
不,绝对不是这样的,请不要发布虚假信息。当参数的类型未声明时,默认促销适用于该参数类型,因此_Bool会被隐式转换为int。 - Jim Balter
2
@Jack:_Bool绝对不是int的typedef。_Bool是一个关键字,它是一个独立的类型。 - Keith Thompson
显示剩余5条评论
5个回答

13

_Bool类型没有特定的转换长度修饰符。

_Bool是一个无符号整数类型,大小足以存储值01。您可以使用以下方式打印_Bool

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

由于整数提升规则,_Bool保证能够提升到int


%u 也同样适用,特别是对于像我这样喜欢始终使用无符号类型的人来说。此外,我认为 _Bool b = true; 更好些。 - Jim Balter
1
这是目前最正确的答案 - _Bool将被提升为int,而不是unsigned int。为了后世留存,如果答案包含指定此行为的C99标准的参考资料,那就太好了。 - Richard Hansen
1
默认参数推广的省略号对应的参数,请参考6.5.2.2p7;默认参数提升的定义,请参考6.5.2.2p6;整数提升,请参考6.3.1.1。 - Richard Hansen

6

在C99之前,bool不是标准的C语言类型,因此它不能作为printf格式化符存在。C99定义了_Bool(您正在使用),将其定义为整数,因此从机器的角度来看,您可以将其转换为整数进行显示。或者,您可以执行以下操作:

printf("%d",foo?1:0);

4
如果您想将一个字符串作为输出打印出来,可以使用以下代码:printf("foo: %s\n", foo ? "true" : "false");其中,如果变量foo为真,则输出“true”,否则输出“false”。请注意格式不要改变,只需进行翻译。 - Jite
当然,那种选择也可以工作,并且可能更容易输入。但是,我对打印“_Bool”的各种方法不太感兴趣,而是确认是否没有用于“_Bool”的长度修饰符或转换说明符。(奖励是一个讨论链接,解释为什么它不存在:疏忽?认为不必要?) - Richard Hansen
以上评论中的回答是正确的:不需要进行强制转换,因为它会自动提升...所以也不需要使用?:。而且,在C99之前没有printf修饰符这一事实是无关紧要的;当他们添加_Bool时,他们本可以添加一个修饰符...但如果他们这样做了,它将打印"true"或"false"。 - Jim Balter
@RichardHansen 你可以通过在线获取并阅读标准草案(官方标准发布前后都有免费的工作草案),来确定有哪些printf格式以及更多信息...只需Google搜索C99标准即可。 - Jim Balter
@RichardHansen 您也可以在线获取C99解释。然而,那里没有提到用于_Bool的printf格式(这是可以预料的,因为它主要解释了为什么要做某些事情,而不是为什么不做)。 - Jim Balter

2

根据你在给@Jack的评论中所述,“6.3.1.1p1说,_Bool的转换等级低于所有其他标准整数类型的等级。”

在调用printf时,charshort将被提升并作为int(或unsigned int)传递到堆栈上,因此我认为使用%d作为格式说明符是可以的。这也意味着您不需要显式转换为int,因为这将自动发生。

唯一可能出现的问题是编译器如何表示_Bool,这可能是实现定义的,并且可能会因一个编译器而异。 我看到两个可能的实现 - 0和1或0和-1。

为了达到最大的可移植性,遵循@user325181的答案,使用三元运算符选择两个选项之一。要么是整数(编译器可以优化掉),要么是字符串。

编辑:如其他答案所述,_Bool被定义为可以存储0或1的无符号整型。 由于它将被提升到unsignedint并传递给printf(),因此我认为%u%d是最合适的说明符。


2
无法将除01以外的任何值存储到_Bool中(6.3.1.2)。 因此,转换回int将始终产生01(除非出现未定义行为)。 - ecatmur
@ecatmur:是的,在<stdbool.h>中,宏falsetrue分别扩展为01 - Keith Thompson
C语言中, _Bool是一种无符号整数类型,因此-1不可行。 - ouah
1
C99 6.3.1.1p2 表示:“如果一个 int 可以表示原始类型的所有值,则该值将转换为 int;否则,它将转换为 unsigned int。” 由于 int 可以表示 _Bool 的所有值,因此它将被提升为 int,而不是 unsigned int(即使 _Bool 是无符号整数类型)。 - Richard Hansen

1

没有。只需使用%d%i说明符,像处理int一样处理它。

_Bool

在C99中,引入了一个新的关键字_Bool作为新的布尔类型。 在许多方面,它的行为很像无符号整数,但是从其他整数类型或指针进行的转换总是限制为0和1。 除了其他无符号类型之外,正如人们对于布尔类型所期望的那样,如果问题表达式的求值结果为0,则此类转换为0,否则为1。 头文件stdbool.h提供了宏bool、true和false,它们分别定义为_Bool、1和0。

实现它的第一种方式是使用char或(int8_t)一个enumbit fields。但实际上,这取决于情况。它可以是typedefint(如我所提到的,它被使用,但不建议,容易出现错误)或charunsigned int或枚举和#define通常使用。

例如,苹果公司的实现使用int,如下所示:

#ifndef _STDBOOL_H_
#define _STDBOOL_H_ 

#define __bool_true_false_are_defined   1

#ifndef __cplusplus

#define false   0
#define true    1

#define bool    _Bool
#if __STDC_VERSION__ < 199901L && __GNUC__ < 3
typedef int _Bool;
#endif

#endif /* !__cplusplus */

#endif /* !_STDBOOL_H_ */

其他实现方式:

typedef int8_t _Bool;

typedef enum { false = 0, true = 1 } bool;

typedef unsigned char Boolean; typedef _Bool Boolean;


1
而且这些实现都不是C99。 _Bool是C99中的关键字,在任何头文件中都找不到它的定义。在上面的苹果示例中,它为C99之前的版本定义了它。在您的其他示例中,您有一个bool类型和一个Boolean类型,该类型被定义为unsigned char_Bool - tomlogic

0

我在Java的printf()中使用了%b转换说明符。最近我尝试了一下,令我惊讶的是它居然起作用了。

这是代码行:

System.out.printf("firstRobot == secondRobot: %b",firstRobot == secondRobot);

这是输出结果:

firstRobot == secondRobot: false

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