为什么sizeof(a?true:false)给出四个字节的输出?

我有一个关于sizeof运算符与三元运算符的一小段代码:

 #include <stdio.h> #include <stdbool.h> int main() { bool a = true; printf("%zu\n", sizeof(bool)); // Ok printf("%zu\n", sizeof(a)); // Ok printf("%zu\n", sizeof(a ? true : false)); // Why 4? return 0; } 

输出( GCC ):

 1 1 4 // Why 4? 

但在这儿,

 printf("%zu\n", sizeof(a ? true : false)); // Why 4? 

三元运算符返回booleantypes,size的booltypes是C中的1个字节。

那么为什么sizeof(a ? true : false)给出了四个字节的输出?

这是因为你有#include <stdbool.h> 。 这个头文件定义macros的 false10 ,所以你的语句如下所示:

 printf("%zu\n", sizeof(a ? 1 : 0)); // Why 4? 

sizeof(int)在你的平台上是4。

这里,三元运算符返回booleantypes,

好的,还有更多!

在C中, 这个三元操作的结果是inttypes的。 [下面的注释(1,2)]

因此,结果与您的平台上的expression式sizeof(int)相同。


注1:引用C11 ,章节§7.18, Boolean type and values <stdbool.h>

[…]其余的三个macros适用于#if预处理指令。 他们是

true

其展开为整数常数1,

false

扩展到整数常量0,[…]

注2:对于条件操作符,§6.5.15( 强调我的

第一个操作数被评估; 在其评估和第二或第三操作数的评估之间有一个顺序点(以评估者为准)。 第二个操作数仅在第一个操作数比较不等于0时才被计算; 第三个操作数仅在第一个操作数比较等于0时才被评估; 结果是第二个或第三个操作数的值(以评估者为准), […]

如果第二个和第三个操作数都具有算术types,那么将由通常的算术转换确定的结果types应用于这两个操作数,结果的types。 [….]

因此,结果将是整型,由于值的范围,这些常量正好是inttypes的。

也就是说,一个通用的build议, int main()最好是int main (void) ,真正符合标准。

三元运算符是一个红色的鲱鱼。

  printf("%zu\n", sizeof(true)); 

打印4(或任何sizeof(int)在您的平台上)。

下面假定boolchar或者大小为1的类似types的同义词,并且int大于char

sizeof(true) != sizeof(bool)sizeof(true) == sizeof(int)很简单,因为true 不是一个booltypes的expression式。 这是一个inttypes的expression式。 在stdbool.h中将#define d设置为1

C中根本不存在typesboolbool 即使用作sizeof的参数,每个这样的右值立即被提升为int 编辑:这个段落不是真的, sizeof参数不会被提升为int 。 尽pipe如此,这并不影响任何结论。

关于C中的布尔types

在1999年,一种布尔types在C语言中引入相当晚。在此之前,C没有布尔types,而是对所有布尔expression式使用int 。 因此所有逻辑运算符如> == ! 等返回一个值为10int

这是自定义的应用程序使用自制的types,如typedef enum { FALSE, TRUE } BOOL; ,这也归结为int sizedtypes。

C ++有一个更好的,明确的布尔types, bool ,不大于1个字节。 尽pipeC中的布尔types或expression式在最坏的情况下最终会变成4字节。 用C ++标准在C语言中引入了一些与C ++兼容的方法。 C然后得到一个布尔types_Bool和头stdbool.h

stdbool.h提供了一些与C ++的兼容性。 这个头文件定义了macrosbool (与C ++关键字相同的拼写),扩展为_Bool ,这是一个小整数types,可能是1个字节。 同样,头文件提供了两个macros,分别是truefalse ,与C ++关键字相同, 但与旧的C程序兼容 。 因此,C和C中的truefalse展开为10 ,它们的types是int 。 这些macros实际上不是像对应的C ++关键字那样的布尔types。

同样,为了向后兼容的目的,C中的逻辑运算符仍然返回一个int到今天,即使现今的C有一个布尔types。 在C ++中,逻辑运算符返回一个bool 。 因此,诸如sizeof(a == b)类的expression式将在C中给出int的大小,而在C ++中给出bool的大小。

关于条件操作符?:

条件运算符?:是一个奇怪的运算符,有一些怪癖。 这是一个常见的错误,相信它是100%相当于if() { } else {} 。 不完全的。

在第一个和第二个或第三个操作数的评估之间有一个顺序点。 ?:操作符保证只评估第二个或第三个操作数,所以它不能执行未被评估的操作数的任何副作用。 代码如true? func1() : func2() true? func1() : func2()不会执行func2() 。 到现在为止还挺好。

但是 ,有一个特殊的规则,说明第二个和第三个操作数必须通过常规的算术转换相互进行隐式types提升和平衡。 ( 在这里解释隐含types的促销规则 )。 这意味着第二个或第三个操作数总是至less和int一样大。

所以, truefalse发生在C语言中并不重要,因为expression式总是至less给出一个int的大小。

即使你将expression式重写为 sizeof(a ? (bool)true : (bool)false) 它仍然会返回 int 的大小

这是因为通过通常的算术转换隐式types提升。

快速回答:

  • sizeof(a ? true : false)计算结果为4因为truefalse<stdbool.h>分别定义为10 ,所以expression式展开为sizeof(a ? 1 : 0) ,它是一个inttypes的整数expression式,在您的平台上占用4个字节。 出于同样的原因, sizeof(true)也会在您的系统上评估为4

但请注意:

  • sizeof(a ? a : a)也会计算为4因为三元运算符对其第二个和第三个操作数执行整数提升(如果这些操作数是整数expression式)。 sizeof(a ? true : false)sizeof(a ? (bool)true : (bool)false)当然会发生同样的情况,但将整个expression式转换为bool行为与预期相同: sizeof((bool)(a ? true : false)) -> 1

  • 还要注意比较运算符计算为布尔值10 ,但是具有inttypes: sizeof(a == a) -> 4

唯一保持a的布尔性质的运算符是:

  • 逗号运算符: sizeof(a, a)sizeof(true, a)在编译时计算为1

  • 赋值运算符: sizeof(a = a)sizeof(a = true)的值均为1

  • 增量运算符: sizeof(a++) -> 1

最后,以上所有内容仅适用于C语言:C ++在booltypes,布尔值truefalse ,比较运算符和三元运算符方面具有不同的语义:所有这些sizeof()expression式在C ++中计算为1

这里是包含在源代码中的一个片段

 #ifndef __cplusplus #define bool _Bool #define true 1 #define false 0 #else /* __cplusplus */ 

macros和false分别声明为1和0。

然而在这种情况下,types是文字常量的types。 0和1都是整型常量,适合int,所以它们的types是int。

在你的情况下sizeof(int)是4。

在C中没有布尔数据types,而是逻辑expression式计算为整数值1 ,否则为0

ifforwhilec ? a : b这样的条件expression式c ? a : b c ? a : b期望一个整数,如果数字非零,除了一些特殊的情况外,它被认为是true ,这里是一个recursion和函数,其中三元运算符将评估true直到n达到0

 int sum (int n) { return n ? n+sum(n-1) : n ; 

它也可以用来检查NULL指针,这里是一个recursion函数,用来打印单链表的内容。

 void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }