首页 文章

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

提问于
浏览
129

我有一小段关于带有三元运算符的 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;
}

Output (GCC):

1
1
4 // Why 4?

但在这里,

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

三元运算符返回 boolean 类型,sizeof bool 类型在C中为 1 字节 .

然后 why does sizeof(a ? true : false) give an output of four bytes?

7 回答

  • 1

    这是因为你有 #include <stdbool.h> . Headers defines macros truefalse10 ,所以你的语句如下所示:

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

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

  • 222

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

    好的,还有更多!

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

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


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

    [....]其余三个宏适用于#if预处理指令 . 它们是真的,它扩展为整数常量1,false,它扩展为整数常量0,[....]

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

    评估第一个操作数;在其评估与第二或第三操作数的评估之间存在一个序列点(以评估者为准) . 仅当第一个操作数不等于0时才评估第二个操作数;仅当第一个操作数比较等于0时才评估第三个操作数;结果是第二个或第三个操作数的值(无论哪个被评估),[...]

    如果第二个和第三个操作数都有算术类型,那么通常算术转换确定的结果类型是应用于这两个操作数的结果类型 . [....]

    因此,结果将是整数类型,并且由于值范围,常量的类型为 int .

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

  • -2

    三元运算符是红鲱鱼 .

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

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

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

    sizeof(true) != sizeof(bool)sizeof(true) == sizeof(int) 之所以仅仅因为 truenotbool 类型的表达式 . 它是 int 类型的表达式 . 在 stdbool.h#define1 .

    C中根本没有rol类型的rvalues . 即使用作sizeof的参数,每个这样的rvalue也会立即提升为int . 编辑:此段落不正确, sizeof 的参数不会升级为 int . 但这并不影响任何结论 .

  • 66

    Regarding the boolean type in C

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

    应用程序可以自定义使用自制类型,例如 typedef enum { FALSE, TRUE } BOOL; ,它也归结为 int -sized类型 .

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

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

    类似地,为了向后兼容的目的,C中的逻辑运算符仍然返回 int 到今天,即使C现在有一个布尔类型 . 在C中,逻辑运算符返回 bool . 因此,诸如 sizeof(a == b) 之类的表达式将在C中给出 int 的大小,但在C中给出 bool 的大小 .

    Regarding the conditional operator ?:

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

    在第1和第2或第3操作数的评估之间存在序列点 . 保证 ?: 运算符仅评估第2或第3个操作数,因此它不能执行未计算的操作数的任何副作用 . 像 true? func1() : func2() 这样的代码不会执行 func2() . 到现在为止还挺好 .

    但是,有一个特殊的规则,规定第二个和第三个操作数必须隐式类型提升并对每个操作数进行 balancer 其他与通常的算术转换 . (Implicit type promotion rules in C explained here) . 这意味着第二个或第三个操作数将始终至少与 int 一样大 .

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

    Even if you would rewrite the expression to sizeof(a ? (bool)true : (bool)false) it would still return the size of an int !

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

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

    保持 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 .

  • 58

    以下是源代码中包含的内容片段

    #ifndef __cplusplus
    
    #define bool    _Bool
    #define true    1
    #define false   0
    
    #else /* __cplusplus */
    

    truefalse 分别声明为1和0 .

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

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

  • 30

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

    ifforwhilec ? a : b 这样的条件表达式期望一个整数,如果该数字非零,则除了一些特殊情况外,它被认为是 true ,这里是一个递归求和函数,其中三元运算符将评估 true ,直到 n 到达 0 .

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

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

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

相关问题