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

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

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

三元运算符 returns boolean 类型和 sizeof bool 类型在 C 中是 1 字节。

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

Here, ternary operator return boolean type,

好的,还有更多内容!

在C中,this三元运算的结果是int类型。 [下面注释(1,2)]

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


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

[....] 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,(强调我的

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. [....]

因此,结果将是整数类型,并且由于取值范围,常量恰好是 int 类型。

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

因为你有#include <stdbool.h>。 header defines macros truefalse10,因此您的语句如下所示:

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

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

三元运算符是一个转移注意力的问题。

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

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

以下假定boolchar的同义词或大小为1的类似类型,int大于char

之所以sizeof(true) != sizeof(bool)sizeof(true) == sizeof(int)只是因为true不是类型bool的表达式。它是 int 类型的表达式。 #defined 为 stdbool.h 中的 1

C 中根本没有 bool 类型的右值。每个这样的右值都会立即提升为 int,即使用作 sizeof 的参数。 编辑:这一段不正确,sizeof 的参数没有得到晋升为 int。不过这并不影响任何结论。

快速回答:

  • 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.

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

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

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

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

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

关于C中的boolean类型

布尔类型在 C 语言中引入的时间相当晚,在 1999 年。在此之前,C 没有布尔类型,而是对所有布尔表达式使用 int。因此,所有逻辑运算符,例如 > == ! 等 return 和值 10int

应用程序习惯使用 home-made 类型,例如 typedef enum { FALSE, TRUE } BOOL;,这也归结为 int 大小的类型。

C++ 有一个更好的显式布尔类型 bool,它不大于 1 个字节。而 C 中的布尔类型或表达式在最坏的情况下最终会变成 4 个字节。 C99 标准在 C 中引入了与 C++ 兼容的某种方式。 C 然后得到一个布尔类型 _Bool 和 header stdbool.h.

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

同样,出于向后兼容的目的,C 中的逻辑运算符 仍然是 return 和 int 直到今天,即使 C 现在有布尔类型.而在 C++ 中,逻辑运算符 return a bool。因此,像 sizeof(a == b) 这样的表达式在 C 中会给出 int 的大小,但在 C++ 中会给出 bool 的大小。

关于条件运算符?:

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

第一个和第二个或第三个操作数的计算之间有一个序列点。 ?: 运算符保证只评估第二个或第三个操作数,因此它不能执行未评估的操作数的任何 side-effects 。 true? func1() : func2() 之类的代码不会执行 func2()。到目前为止,还不错。

但是,有一条特殊规则规定第二个和第三个操作数必须通过通常的算术转换[=隐式类型提升和相互平衡。 (Implicit type promotion rules in C explained here)。这意味着第二个或第三个操作数将 始终 至少与 int.

一样大

所以 truefalse 恰好是 C 中的 int 类型并不重要,因为表达式总是至少给出 [=10] 的大小=] 不管。

即使您将表达式重写为 sizeof(a ? (bool)true : (bool)false) 它仍然 return 一个 int 的大小!

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

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

ifforwhilec ? 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); }

这是源代码中包含的片段

#ifndef __cplusplus

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

#else /* __cplusplus */

truefalse分别声明为1和0。

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

而你的 sizeof(int) 是 4.