【问题标题】:Behavior of "comma" operator in sizeof() operator In C [duplicate]C中sizeof()运算符中“逗号”运算符的行为[重复]
【发布时间】:2018-03-30 03:31:24
【问题描述】:

我写了关于sizeof 运算符的代码。如果我写类似:

#include <stdio.h>

int main() {
    char a[20];
    printf("%zu\n", sizeof(a));
    return 0;
}

输出:

20 // Ok, it's fine

但是,如果我像这样使用 逗号 运算符:

#include <stdio.h>

int main() {
    char a[20];
    char b;
    printf("%zu\n", sizeof(b, a));
    return 0;
}

输出:

8 // Why the output 8?

所以,我有一个问题:

  • 为什么编译器会在第二个示例中给出输出 8
  • comma 运算符转换为sizeof() 运算符的行为是什么?

【问题讨论】:

    标签: c arrays sizeof comma c11


    【解决方案1】:

    逗号运算符对sizeof没有特殊意义。

    sizeof(b, a) 检查完整的表达式(b, a),计算出结果类型,并计算该类型的大小,而不实际评估(b , a)。正如 chqrlie 在 cmets 中所指出的,() 是表达式的一部分,用于计算(结果的)大小。

    在这种情况下,b 是一个 chara 是一个数组。如果要计算表达式b, a,则首先计算b,结果将被丢弃。然后a 将转换为值等于&amp;a[0] 的指针(char *),这将是表达式(b, a) 的结果。

    由于b, a 的结果是char * 类型,所以sizeof(b,a) 等于sizeof (char *)。这是一个实现定义的值,但对于您的编译器而言,其值为 8(这可能意味着代码正在构建为 64 位应用程序)。

    【讨论】:

    • sizeof(b, a) 检查完整的表达式 b, a... 从技术上讲,sizeof(b, a) 检查完整的表达式 (b, a)。但有趣且令人困惑的是,sizeof((a)) 仍会产生 20 的值。
    • sizeof(b, a) examines the complete expression b, a 我认为括号是第一个评估的,然后 sizeof 将评估结果。不是吗?
    • @Michi 括号(在此上下文中)不是运算符
    • @M.M 我从来没有这么说过:)。我说的是那些括号内发生的事情,这是首先评估的,只有在 SIZEOF 评估结果之后。或者我错了。
    • True-sizeof(b,a) 计算表达式 (b,a) 的结果大小。从语法上讲,sizeof(int) 需要在类型名称周围加上()(因此sizeof int 无效),而sizeof expression 不需要(),并且()(如果使用)是表达式的一部分。我会尽快编辑以反映这一点。
    【解决方案2】:

    在大多数情况下,数组衰减为指针。所以带有逗号运算符的b,a 的类型是char*(不再是char[20])。在你的机器上,指针是 8 个字节。

    顺便说一句,我认为在某些逗号运算符上使用sizeof 确实会让读者感到困惑。我建议在简单表达式或类型上使用sizeof

    (我刚刚发现这是 C 和 C++ 之间的棘手差异之一;请参阅 this explanation

    【讨论】:

    • Reference is C11 6.3.2.1/3: "除非它是sizeof 运算符、_Alignof 运算符或一元&amp; 运算符的操作数,或者是字符串文字用于初始化数组,类型为''array of type''的表达式被转换为类型为''pointer to type''的表达式,它指向数组对象的初始元素并且不是左值。"
    • 这是一个很奇怪的问题,但在 ba 的评估之间存在逗号运算符和序列点这一事实可能会导致与该参考 C11 6.5.17/2 逗号冲突操作员。我不知道答案,但如果 b 被评估为注入序列点的 void 指针,a 似乎将转换为指针。
    • @DavidC.Rankin 既不评估 b 也不评估 a,因为它们是 sizeof 操作数的一部分。序列点与此无关
    • C11 6.5.17/3 表示逗号运算符不能作为函数的参数出现。现在sizeof 本身并不是一个函数。我当然会在这里听从你的解释。我不知道,但想确保我清楚地理解 - 以及竞争的 cmets 和答案 - 我不知道:( 我所能做的就是阅读,标准说“a 的左操作数逗号运算符被计算为 void 表达式"... "然后计算右操作数;"
    • “这个解释” 是完全一样的。你为什么不投票关闭?
    【解决方案3】:

    C 语言是一种左值丢弃 语言。 C 中的逗号运算符不会产生左值,也不会保留数组的“数组性”。这意味着当右侧操作数是一个数组时,它会立即进行数组到指针的转换。因此,在 C 中,逗号运算符的结果是 char * 类型的右值。这就是您将sizeof 应用到的内容。这就是为什么你会得到8 的原因,它是你平台上的指针大小。

    C++ 语言是一种保留左值的语言。 C++ 中逗号运算符的右手操作数进行左值到右值的转换,如果操作数是数组,它会保持其左值性和数组类型。在 C++ 中,逗号运算符的结果是 char[20] 类型的左值。这就是您将sizeof 应用到的内容。这就是为什么你得到20 的原因。

    【讨论】:

    • 这里的整个故事是因为那些括号,与 sizeof 运算符无关。就像我在评论中所说的那样,如果你这样做 int a = (1,2,3); 它可以工作,但如果你这样做 int a = 1,2,3; 它不会因为缺少这些括号。我想你知道方法。
    • @Michi:确实“括号与 sizeof 运算符无关”。但在这种情况下,我看不到这一点的重要性。代码编译 - 这是给定的。
    • 这里的重点是人们应该停止将 SIZEOF 运算符视为一个函数,他们可以避免这样的事情。他们只关注 SIZEOF 而不是右侧的确切内容。
    • @Michi:“避免”?究竟要避免什么?我在这个主题中看不到任何旨在说服任何人“避免”任何事情的内容。这个问题相当技术性和中性。作者很清楚, 在这种情况下是一个逗号运算符,而不是函数参数分隔符。
    • 哇,不知道 C 和 C++ 之间的区别。今天学到了一些东西:-)
    【解决方案4】:

    sizeof 根据其操作数的类型确定大小。在sizeof(a) 中,a 不会衰减为指向它的第一个元素的指针,a 的类型将是char[20]。而在sizeof(b, a) 中,a 是逗号运算符的右操作数,在这种情况下,它将衰减为指向其第一个元素的指针,而表达式b , a 的类型将为char *。因此,sizeof(b, a) 将返回 char * 数据类型的大小。

    在 C++ 中,, 运算符的结果是一个左值(不像在 C 中它产生一个右值)。在这种情况下,sizeof(b, a) 将返回数组 a 的大小。

    【讨论】:

    • @chqrlie;哎呀!感谢您挑选它。
    猜你喜欢
    • 2018-02-23
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-11
    • 2010-12-16
    • 1970-01-01
    • 2020-07-14
    相关资源
    最近更新 更多