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


133

我有一小段关于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?

三元运算符返回booleantype,sizeof bool类型为1C中的字节。

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


39
sizeof(true)并且sizeof(false)也是4:ide.geeksforgeeks.org/O5jvuN
tkausl

7
这里更有趣的问题是,为什么这个实现“不一致”,因为它明显地定义_Bool有大小为1,但不truefalse。但是据我所知,该标准对此无话可说。

12
@FelixPalmen给出char a; sizeof(a) == 1和的原因相同sizeof('a') == sizeof(int)(用C表示)。这与实现无关,而与语言有关。
n。代词

10
您是否尝试打印sizeof(true)?也许这会使细化变得更加清晰(特别是,三元运算符是一个红色鲱鱼会变得很明显)。
n。代词

4
@FelixPalmen true#defined等于1,stdbool.h所以是的,这是字面量定义。
n。代词

Answers:


223

这是因为你有#include <stdbool.h>。该标头将宏定义为, true并且false10,因此您的语句如下所示:

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

sizeof(int) 在您的平台上为4。


21
“这是因为您有#include <stdbool.h>”不,不是。sizeof(a ? (uint8_t)1 : (uint8_t)0);也会得出结果4。在?:这里,操作数的整数提升是重要的部分,而不是trueand 的大小false
伦丁

9
@伦丁:两者都很重要。按照书面形式,该类型已经int没有提升。您无法“修复”它的原因是默认促销。
R .. GitHub STOP HELPING ICE

5
@PeterSchneider这不是C ++。这是C.在C ++中,true并且false宏; 他们是关键词。不是将它们定义为10,而是将其定义为bool类型的true和false值。
贾斯汀

5
@PeterSchneider不,您今天学到了一些有关C的知识。不要混淆这两种语言。在C ++中,sizeof(true)是1. demo
Rakete1111年

1
是的,把它弄混了。没有仔细阅读,并且被cppreference-link误导了。我的错,谢谢。但是我仍然对C ++有这种感觉。
彼得·施耐德

66

在这里,三元运算符返回boolean类型,

好的,还有更多!

在C中,三元运算的结果为类型int[以下注意事项(1,2)]

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


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

[....]其余三个宏适合在#if预处理指令中使用。他们是

true

扩展为整数常数1

false

扩展为整数常量0,[....]

注2:对于条件运算符,第6.5.15节(强调我的内容

计算第一个操作数;在它的评估与第二个或第三个操作数的评估(无论哪个被评估)之间都有一个序列点。仅当第一个操作数比较不等于0时,才对第二个操作数求值;仅当第一个操作数等于0时,才计算第三个操作数;结果是第二个或第三个操作数的值(以所评估的为准), [...]

如果第二个操作数和第三个操作数都具有算术类型,则将它们应用到这两个操作数时,将由通常的算术转换确定的结果类型。[....]

因此,结果将是整数类型,并且由于值的范围,这些常数恰好是类型int

也就是说,一般性建议int main()最好int main (void)是真正符合标准。


@ user694733 umm ..为什么不呢?<stdbool.h>将MACROS定义为int.. 类型吗?
Sourav Ghosh

@BasileStarynkevitch好吧,我现在知道了,这似乎确实是错误的,现在更新。
Sourav Ghosh

58

三元运算符是红色鲱鱼。

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

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

以下假设boolchar大小1 的同义词或类似类型,并且int大于char

之所以sizeof(true) != sizeof(bool)sizeof(true) == sizeof(int)很简单,因为true没有类型的表达式bool。这是type的表达int。据#defined为1 1stdbool.h

boolC 中根本没有类型的右值。每个这样的右值都会立即提升为int,即使用作的参数也是如此sizeof编辑:此段不正确,sizeof不要将参数提升为int。但是,这不会影响任何结论。


好答案。在阅读了目前最受好评的答案之后,我认为所有语句的评估结果应为4。+1
Pedro A

5
是不是(bool)1右值类型bool
Ben Voigt

printf("%u\n", sizeof((char) 1));1在我的平台上打印,而在上printf("%u\n", sizeof(1));打印4。这是否意味着您的陈述“即使将每个右值用作sizeof的参数,每个这样的rvalue都会立即提升为int”是假的吗?
JonatanE

这并不能真正回答问题。trueetc 的大小和类型实际上并不重要,?:因为int无论如何它都会被整数提升。也就是说,答案应该说明为什么 ?:是红色鲱鱼。
伦丁

6
我认为答案以最佳方式解决了这个问题。欢迎您拒绝或改进它。
n。代词

31

关于C语言中的布尔类型

布尔类型是在1999年C语言的较晚引入的。在此之前,C没有布尔类型,而是用于int所有布尔表达式。因此,所有逻辑运算符(例如> == !etc)都返回intvalue 10

对于应用程序,使用诸如的自制类型是自定义的typedef enum { FALSE, TRUE } BOOL;,它也可以归结为int大小类型。

C ++具有更好,更明确的布尔类型bool,该类型不大于1个字节。在最坏的情况下,C语言中的布尔类型或表达式最终将以4个字节结尾。带有C99标准的C语言引入了与C ++的某种兼容方式。C然后得到一个布尔类型_Bool以及标题stdbool.h

stdbool.h提供与C ++的一些兼容性。此标头定义了bool扩展为的宏(与C ++关键字的拼写相同)宏_Bool,该类型是小整数类型,可能大了1个字节。同样,标头提供了两个宏truefalse,其拼写与C ++关键字相同,但与较旧的C程序具有向后兼容性。因此true,在C中false扩展为1and 0,它们的类型为int。这些宏实际上不是布尔类型的,就像相应的C ++关键字那样。

同样,出于向后兼容的目的,即使C如今具有布尔类型,C中的逻辑运算符仍会返回int到今天。在C ++中,逻辑运算符返回bool。因此,诸如的表达式sizeof(a == b)将给出intC中a的大小,但给出boolC ++ 中a的大小。

关于条件运算符 ?:

条件运算符?:是一个怪异的运算符,有几个怪癖。普遍认为它等于100%是一个普遍的错误if() { } else {}。不完全的。

在第一个和第二个或第三个操作数的求值之间有一个序列点。该?:操作员是保证仅评估任一第二或第三操作数,所以它不能执行该不评估操作数的任何副作用。像这样的代码true? func1() : func2()将不会执行func2()。到目前为止,一切都很好。

但是,有一条特殊的规则指出,第二个操作数和第三个操作数必须通过常规的算术转换隐式地提升并相互平衡。(此处解释了C中的隐式类型提升规则)。这意味着第二或第三操作数将始终至少与一样大int

因此,这并不重要,true并且false碰巧是intC语言中的类型,因为表达式始终至少会给出intno 的大小。

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

这是由于通过常规算术转换进行的隐式类型提升。


1
C ++实际上并不保证sizeof(bool)==1
aschepler '17

1
@aschepler不,但是C ++标准之外的真实世界可以保证这一点。命名一个不为1的编译器
。– Lundin

你好 我认为,如果没有第一部分,这个答案会更好。第二部分回答问题。其余的虽然有趣,但只是噪音。
YSC

@YSC最初被标记为C和C ++,因此必须对它们的不同布尔类型和它们背后的历史进行比较。我怀疑如果不为C ++标签编写第一部分。但是,人们必须理解为什么的sizeof(布尔)是1,但的sizeof(假)是4 C.
Lundin的

21

快速回答:

  • sizeof(a ? true : false)计算结果为4,因为truefalse在定义<stdbool.h>10分别的,所以表达膨胀到sizeof(a ? 1 : 0)它是一个整数表达类型int,占据在平台上的4个字节。出于相同的原因,在您的系统上sizeof(true)也会求值4

但是请注意:

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

  • 还请注意,比较运算符的计算结果为布尔值10,但int类型为sizeof(a == a) -> 4

保留boolean性质的唯一运算符a是:

  • 逗号操作符:既sizeof(a, a)sizeof(true, a)评估,以1在编译时。

  • 赋值运算符:sizeof(a = a)sizeof(a = true)都具有的值1

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

最后,以上所有内容仅适用于C:C ++在bool类型,布尔值truefalse比较运算符和三元运算符方面具有不同的语义:所有这些sizeof()表达式1在C ++中求值。


2
一个好的答案实际上可以指出,什么类型truefalse是什么并不重要,因为无论如何?:操作数都会被提升为整数int。这样sizeof(a ? (uint8_t)true : (uint8_t)false)也将得到4。
伦丁

该答案涵盖了重要的要点,价值被提升至int
Chinni

1

这是源代码中包含的摘录

#ifndef __cplusplus

#define bool    _Bool
#define true    1
#define false   0

#else /* __cplusplus */

truefalse分别声明为1和0。

但是,在这种情况下,类型是文字常量的类型。0和1都是适合int的整数常量,因此它们的类型为int。

sizeof(int)您的情况是4。


-3

C中没有布尔数据类型,相反,如果逻辑表达式为1true ,则逻辑表达式的值为整数0

条件表达式喜欢ifforwhile,或c ? a : b期待一个整数,如果数字是非零它被认为是true除了一些特殊情况下,这里的递归求和函数中三元运营商将评估true,直到n到达0

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

它也可以用来NULL检查指针,这是一个递归函数,用于打印单链接列表的内容。

void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.