为什么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?
三元运算符返回boolean
types,size的bool
types是C中的1
个字节。
那么为什么sizeof(a ? true : false)
给出了四个字节的输出?
这是因为你有#include <stdbool.h>
。 这个头文件定义macros的 false
为1
和0
,所以你的语句如下所示:
printf("%zu\n", sizeof(a ? 1 : 0)); // Why 4?
sizeof(int)
在你的平台上是4。
这里,三元运算符返回
boolean
types,
好的,还有更多!
在C中, 这个三元操作的结果是int
types的。 [下面的注释(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。 [….]
因此,结果将是整型,由于值的范围,这些常量正好是int
types的。
也就是说,一个通用的build议, int main()
最好是int main (void)
,真正符合标准。
三元运算符是一个红色的鲱鱼。
printf("%zu\n", sizeof(true));
打印4(或任何sizeof(int)
在您的平台上)。
下面假定bool
是char
或者大小为1的类似types的同义词,并且int
大于char
。
sizeof(true) != sizeof(bool)
和sizeof(true) == sizeof(int)
很简单,因为true
不是一个bool
types的expression式。 这是一个int
types的expression式。 在stdbool.h
中将#define
d设置为1
。
C中根本不存在types bool
右bool
。即使用作 编辑:这个段落不是真的, sizeof
的参数,每个这样的右值立即被提升为int
。sizeof
参数不会被提升为int
。 尽pipe如此,这并不影响任何结论。
关于C中的布尔types
在1999年,一种布尔types在C语言中引入相当晚。在此之前,C没有布尔types,而是对所有布尔expression式使用int
。 因此所有逻辑运算符如> == !
等返回一个值为1
或0
的int
。
这是自定义的应用程序使用自制的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,分别是true
和false
,与C ++关键字相同, 但与旧的C程序兼容 。 因此,C和C中的true
和false
展开为1
和0
,它们的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
一样大。
所以, true
和false
发生在C语言中并不重要,因为expression式总是至less给出一个int
的大小。
即使你将expression式重写为 sizeof(a ? (bool)true : (bool)false)
它仍然会返回 int
的大小 !
这是因为通过通常的算术转换隐式types提升。
快速回答:
-
sizeof(a ? true : false)
计算结果为4
因为true
和false
在<stdbool.h>
分别定义为1
和0
,所以expression式展开为sizeof(a ? 1 : 0)
,它是一个int
types的整数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
。 -
还要注意比较运算符计算为布尔值
1
或0
,但是具有int
types:sizeof(a == a) -> 4
。
唯一保持a的布尔性质的运算符是:
-
逗号运算符:
sizeof(a, a)
和sizeof(true, a)
在编译时计算为1
。 -
赋值运算符:
sizeof(a = a)
和sizeof(a = true)
的值均为1
。 -
增量运算符:
sizeof(a++) -> 1
最后,以上所有内容仅适用于C语言:C ++在bool
types,布尔值true
和false
,比较运算符和三元运算符方面具有不同的语义:所有这些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
。
像if
, for
, while
或c ? 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); }