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

Why does “sizeof(a ? true : false)” give an output of four bytes?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdbool.h>

int main()
{
    bool a = true;
    printf("%zu
"
, sizeof(bool));  // Ok
    printf("%zu
"
, sizeof(a));     // Ok
    printf("%zu
"
, sizeof(a ? true : false)); // Why 4?
    return 0;
}

输出(GCC):

1
2
3
1
1
4 // Why 4?

但在这里,

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

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

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


这是因为你有#include 。该头将宏truefalse定义为10,因此您的语句如下:

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

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


Here, ternary operator return boolean type,

好吧,还有更多!

在C语言中,这种三元运算的结果是int类型。[以下注释(1,2)]

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

注1:引用C11,第7.18章,Boolean type and values

[....] The remaining three macros are suitable for use in #if preprocessing directives. They
are

true

which expands to the integer constant 1,

false

which expands to the integer constant 0, [....]

注2:对于条件运算符,第6.5.15章(重点是Mine)

The first operand is evaluated; there is a sequence point between its evaluation and the
evaluation of the second or third operand (whichever is evaluated). The second operand
is evaluated only if the first compares unequal to 0; the third operand is evaluated only if
the first compares equal to 0; the result is the value of the second or third operand
(whichever is evaluated), [...]

If both the second and third operands have arithmetic type, the result type that would be
determined by the usual arithmetic conversions, were they applied to those two operands,
is the type of the result. [....]

因此,结果将是integer类型,并且由于值范围的原因,这些常量正好是int类型。

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


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

1
2
    printf("%zu
"
, sizeof(true));

打印4(或任何平台上的EDOCX1[1])。

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

sizeof(true) != sizeof(bool)sizeof(true) == sizeof(int)的原因仅仅是因为true不是bool型的表达。它是int类型的表达式。它是#defined,在stdbool.h中是1d。

在c中根本没有bool类型的rvalues。每一个这样的值都会立即提升为int,即使当用作sizeof的参数时也是如此。〔s〕edit:This paragraph is not true,arguments to sizeofdon't get promoted to int。但这并不影响任何结论。


关于C中的布尔类型

1999年,布尔类型在C语言中引入得相当晚。在此之前,C没有布尔类型,而是将int用于所有布尔表达式。因此,所有逻辑运算符(如> == !等)都返回值为10int

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

C++有一个更好的,明确的布尔类型,EDOCX1×7,不大于1字节。而在最坏的情况下,C中的布尔类型或表达式将以4个字节结束。在C99标准中,C++中引入了一些与C++兼容的方式。然后,C得到一个布尔型_Bool,以及头部stdbool.h

EDOCX1 9提供了与C++的一些兼容性。这个标头定义了宏EDCOX1的7个字(与C++关键字相同的拼写),扩展到EDCOX1×8,类型是一个小整数类型,可能有1个字节大。类似地,报头提供两个宏EDOCX1,13和EDCOX1,14,同样的拼写作为C++关键字,但与旧C程序向后兼容。因此,truefalse在c中扩展到10,其类型为int。这些宏实际上不是像相应的C++关键字那样的布尔类型。

同样,为了向后兼容的目的,C中的逻辑运算符至今仍返回int,尽管C现在有一个布尔类型。在C++中,逻辑运算符返回EDCOX1×7Ω。因此,一个表达式如EDCOX1(22)将在C中给出EDCOX1×0的大小,但是在C++中EDCOX1的大小为7。

关于条件运算符?:

条件运算符?:是一个奇怪的运算符,有两个奇怪的地方。认为100%等同于if() { } else {}是一个常见的错误。不完全是这样。

在第一个操作数和第二个或第三个操作数的计算之间有一个序列点。保证?:运算符只计算第二个或第三个操作数,因此它不能执行未计算的操作数的任何副作用。像true? func1() : func2()这样的代码不会执行func2()。到目前为止,一切都很好。

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

因此,truefalse恰好是c中的int类型并不重要,因为表达式总是至少给出int的大小。

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

这是因为通过通常的算术转换实现了隐式类型提升。


快速回答:

  • sizeof(a ? true : false)计算为4,因为truefalse中分别定义为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

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

  • 逗号运算符:sizeof(a, a)sizeof(true, a)在编译时对1进行评估。

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

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

最后,所有这些都只适用于C:C++对EDCOX1、14的类型、布尔值EDCOX1、8和EDCOX1、9、比较算子和三元算子有不同的语义:所有这些EDCOX1×63表达式在C++中被评估为EDCOX1×10。


以下是源代码中包含的代码段

1
2
3
4
5
6
7
#ifndef __cplusplus

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

#else /* __cplusplus */

truefalse分别声明为1和0。

但是在这种情况下,类型是文本常量的类型。0和1都是整型常量,适合于int,所以它们的类型是int。

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


C中没有布尔数据类型,而逻辑表达式的计算结果为整数值1,否则为true,否则为0

条件表达式,如ifforwhilec ? a : b期望一个整数,如果数字为非零,则认为true,除某些特殊情况外,这里有一个递归和函数,三元运算符将对true进行计算,直到n达到0

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

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

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