【问题标题】:Explanation of output of program程序输出说明
【发布时间】:2021-02-04 16:08:40
【问题描述】:

谁能解释为什么这个程序打印 4 1 而不是 4 2?

不应该先执行具有较高优先级的预递增运算符并打印 4 2 吗?

#include <stdio.h>
int main() {
   int a=1;
   printf ("%ld %d",sizeof(++a),a);
   return 0;
}

【问题讨论】:

标签: c sizeof operator-precedence


【解决方案1】:

虽然你已经得到了几个答案,但我想再提供一个,因为你的问题实际上包含了三个不同的误解,我想一一谈谈。

首先,sizeof 是一个特殊的运算符,根据定义,它 not 评估它的参数(即,它采用的任何子表达式的大小)。所以sizeof(++a) 确实增加a。而sizeof(x = 5)不会将 5 分配给xsizeof(printf("Hello!")) 不会打印“Hello”。

其次,如果我们去掉sizeof,简单地写

printf("%d %d", ++a, a);

我们将能够使用优先级来找出行为。优先级是一个重要的概念,但总的来说,它不能帮助您找出涉及++ 的混淆操作的行为。

最后,也许令人惊讶的答案是,如果你写

printf("%d %d", ++a, a);

不可能弄清楚它会做什么。它基本上是未定义的。 (特别是:在像printf("%d %d", x, y) 这样的任何函数调用中,unspecified 参数被评估的顺序,所以你不知道是x 还是y 首先被评估——尽管有但是,当其中一个是a 并且其中一个是++a 时,您会遇到a 被修改并使用其值的情况,因此无法知道是否旧的或使用新值,这使得表达式undefined。有关此问题的更多信息,请参阅this question。)

附:还有一个问题我忘了提,正如来自莫斯科的@Vlad 所说:%ld 不是打印sizeof 的结果的可靠方法,它是size_t 类型的值。如果可以,您应该使用%zu,如果不能,则在转换为(unsigned) 后使用%u

【讨论】:

  • "无法弄清楚它会做什么。"因为它可以在之前或之后增加?
  • 这将受益于标准引用
  • @dreamcrash 这是不可能的,因为它本质上是令人困惑的,因为没有定义答案的规则。逗号分隔函数参数不是逗号运算符,也不会引入序列点。因此,如果您调用f(a, a++),则没有规则可以说明传递的第一个参数是a 的旧值还是递增值。此外,这是使整个表达式(以及因此整个程序)未定义的情况之一。
  • 感谢您的解释,这就是为什么人们宁愿做 f(a, a);一个++。
【解决方案2】:

来自 C 标准 *6.5.3.4 的 sizeof 和 alignof 运算符)

2 sizeof 运算符产生其操作数的大小(以字节为单位),即 可以是表达式或类型的括号名称。尺寸是 由操作数的类型决定。结果是一个整数。如果 操作数的类型是变长数组类型,操作数 被评估; 否则,操作数不会被计算并且结果 是一个整数常量

所以sizeof 运算符的任务是确定用作操作数的表达式的类型,然后知道其操作数的类型以返回该类型对象的大小。如果操作数不是可变长度数组,则不计算用作操作数的表达式,并在编译时计算 sizeof 运算符返回的值。

因此调用

printf ("%ld %d",sizeof(++a),a);

相当于调用

printf ("%ld %d",sizeof( int ),a);

在您的系统中,sizeof( int ) 等于 4

因此,使用什么表达式(除了使用在运行时计算其大小的可变长度数组)作为操作数并不重要。重要的是表达式的类型。例如你甚至可以写

printf ( "%zu %d\n", sizeof( ( ++a, ++a, ++a, ++a, ++a ) ), a );

得到了同样的结果。

请注意,您应该使用转换说明符zu 用于size_t 类型的值,而不是ld 用于有符号值。那就是你需要写

printf ("%zu %d",sizeof(++a),a);

【讨论】:

    【解决方案3】:

    根据c99 standard

    sizeof() 运算符只考虑操作数的类型,它可能是表达式或类型的名称(即 int、double、float 等),而不是在评估表达式时获得的值。

    因此,sizeof() 运算符内的操作数不求值。

    【讨论】:

    • C17 明确表示:“如果操作数的类型是变长数组类型,则计算操作数;否则,不计算操作数,结果为一个整数常量。” 6.5.3.4 (2).
    • @NateEldredge 很好的发现。那么C17是最早有这个规定的吗?
    • @EugeneSh.:我没有检查中间的那些。
    • sizeof 的操作数永远不会被计算,否则像 char *p = NULL; p = malloc(length * sikzeof(*p)); 这样的构造将无法工作。
    • @NateEldredge C11 确实没有。 port70.net/~nsz/c/c11/n1570.html#6.5.3.4p2UPD:啊抱歉,确实有
    猜你喜欢
    • 2023-03-07
    • 1970-01-01
    • 2011-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-24
    • 1970-01-01
    相关资源
    最近更新 更多