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

Posted

技术标签:

【中文标题】为啥“sizeof(a ? true : false)”会给出四个字节的输出?【英文标题】:Why does "sizeof(a ? true : false)" give an output of four bytes?为什么“sizeof(a ? true : false)”会给出四个字节的输出? 【发布时间】:2018-04-11 04:14:09 【问题描述】:

我有一小段关于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类型,bool类型的sizeof在C语言中为1字节。

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

【问题讨论】:

sizeof(true)sizeof(false) 也是 4:ide.geeksforgeeks.org/O5jvuN 这里更有趣的问题是为什么这个实现是“不一致的”,因为它显然将_Bool定义为大小为1,而不是truefalse。但据我所知,该标准对此没有任何规定。 @FelixPalmen 给出 char a; sizeof(a) == 1sizeof('a') == sizeof(int) 的相同原因(在 C 中)。这与实现无关,而与语言有关。 您是否尝试打印sizeof(true)?也许它会让细化更清楚一点(特别是,三元运算符很明显是一个红鲱鱼)。 @FelixPalmen true is #defined to be 1 by stdbool.h 所以是的,这是字面定义。 【参考方案1】:

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

好的,还有更多!

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

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


注 1:引用 C11,第 7.18 章,Boolean type and values &lt;stdbool.h&gt;

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

true

展开成整数常数1,

false

展开成整数常量 0,[....]

注 2:对于条件运算符,第 §6.5.15 章,(强调我的

计算第一个操作数;在它的求值和 第二个或第三个操作数的评估(以评估者为准)。第二个操作数 仅当第一个比较不等于 0 时才评估;仅在以下情况下评估第三个操作数 第一个比较等于 0; 结果是第二个或第三个操作数的值 (以评估为准), [...]

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

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

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

【讨论】:

@user694733 嗯..为什么不呢? &lt;stdbool.h&gt; 将 MACROS 定义为 int.. 有错吗? @BasileStarynkevitch 好的,我现在明白了,这似乎确实是错误的,现在更新。【参考方案2】:

因为你有#include &lt;stdbool.h&gt;。那个标题defines macrostruefalse10,所以你的声明看起来像这样:

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

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

【讨论】:

"这是因为你有#include " 不,不是。 sizeof(a ? (uint8_t)1 : (uint8_t)0); 也会给出 4 的结果。?: 操作数的整数提升是这里的重要部分,而不是 truefalse 的大小。 @Lundin:两者都很重要。正如所写,类型已经是int,没有提升。您无法“修复”它的原因是默认促销活动。 @PeterSchneider 这不是 C++。这是 C。在 C++ 中,truefalsenot 宏;它们是关键字。它们没有被定义为10,而是bool 类型的真假值。 @PeterSchneider 不,你今天学到了一些关于 C 的东西。不要混淆这两种语言。在 C++ 中,sizeof(true) 是 1。demo。 没错,搞混了。没有仔细阅读,被 cppreference-link 误导了。我的错,谢谢。但无论如何我对 c++ 有这种感觉。【参考方案3】:

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

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

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

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

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

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

【讨论】:

不错的答案。在我阅读了当前最受好评的答案之后,我认为所有陈述都应该评估为 4。这清除了一切。 +1 (bool)1 不是bool 类型的右值吗? printf("%u\n", sizeof((char) 1)); 在我的平台上打印1,而printf("%u\n", sizeof(1)); 打印4。这是否意味着您的陈述“每个这样的右值都立即提升为 int,即使用作 sizeof 的参数”是错误的? 这并不能真正回答问题。 true 等的大小和类型在 ?: 的情况下并不重要,因为无论如何它都会被整数提升为 int。也就是说,答案应该解决为什么 ?: 是一个红鲱鱼。 我认为答案以最好的方式解决了这个问题。欢迎您投反对票或改进它。【参考方案4】:

快速回答:

sizeof(a ? true : false) 的计算结果为 4,因为 truefalse&lt;stdbool.h&gt; 中分别定义为 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)) -&gt; 1

还请注意,比较运算符的计算结果为布尔值 10,但具有 int 类型:sizeof(a == a) -&gt; 4

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

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

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

自增运算符:sizeof(a++) -&gt; 1

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

【讨论】:

好的答案实际上设法指出truefalse 是什么类型并不重要,因为?: 操作数无论如何都会被整数提升为int。因此sizeof(a ? (uint8_t)true : (uint8_t)false) 也将产生 4 作为结果。 这个答案涵盖了重点,价值提升到int【参考方案5】:

关于 C 中的布尔类型

1999 年,C 语言中很晚才引入布尔类型。在此之前,C 没有布尔类型,而是使用int 来表示所有布尔表达式。因此,所有逻辑运算符(例如 &gt; == ! 等)都返回值为 10int

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

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

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

同样,出于向后兼容的目的,C 中的逻辑运算符 仍然 返回 int,尽管如今 C 有布尔类型。在 C++ 中,逻辑运算符返回 bool。因此,sizeof(a == b) 这样的表达式将给出 C 中 int 的大小,但在 C++ 中给出 bool 的大小。

关于条件运算符?:

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

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

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

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

即使你将表达式重写为 sizeof(a ? (bool)true : (bool)false) 它仍然会返回一个 int

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

【讨论】:

C++ 实际上并不保证sizeof(bool)==1 @aschepler 不,但是 C++ 标准之外的现实世界确实保证了这一点。命名一个不是 1 的编译器。 嗨。我认为这个答案会更好没有它的第一部分。第二部分回答了这个问题。其余的虽然有趣,但只是噪音。 @YSC 这最初被标记为 C 和 C++,因此有必要比较它们不同的 bool 类型和它们背后的历史。如果不是 C++ 标签,我怀疑我会写第一部分。但是,必须理解为什么在 C 中 sizeof(bool) 为 1 而 sizeof(false) 为 4。【参考方案6】:

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); 

【讨论】:

【参考方案7】:

这是一个 sn-p,其中包含在源代码中的内容

#ifndef __cplusplus

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

#else /* __cplusplus */

这里的宏truefalse分别被声明为1和0。

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

你的sizeof(int)是4。

【讨论】:

以上是关于为啥“sizeof(a ? true : false)”会给出四个字节的输出?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?

为啥 CAP 定理中的 RDBMS 分区不能容忍,为啥它可用?