1

这是我无法理解的一小段代码

int x=30, *y, *z;
y=&x; 
z=y;
//y++ = z++;
//*y++ = *z++;
x++;
printf("x=%p, y=%p, z=%p y=%p\n ", &x, y,z,y++);
return 0;

这些疑问一直困扰着我:
为什么(z++ = y++;)无效分配(z = y)有效。这个任务(*y++ = *z++)是什么意思?

此外,如果我运行这个程序,我会得到以下输出:

x = 0028FF04 , y = 0028FF08, z = 0028FF04 y = 0028FF04
而我的期望是
x = 0028FF04 , y = 0028FF04, z = 0028FF04 y = 0028FF08

4

3 回答 3

4

在分配中,有左侧和右侧。左边必须是所谓的左值(l 代表左边),这本质上意味着它必须是一个变量,而不是计算或文字的结果。你可以分配x = 5 + 2,但你不能分配5 + 2 = x

你不能分配,z++ = y++因为z++不是左值。它是一个表达式,其结果是z递增前的值。它不是对变量z或类似的东西的引用。

但是,您可以分配*z++ = *y++,因为在这里您处理指针。本质上左边(右边无关紧要,这里只有左值限制很重要)意味着:增量z,在增量之前获取它的值并取消引用它(所以值z应该是一个地址,它完全是)。这给了你一个有效的左值。

于 2013-09-08T00:20:24.273 回答
2

为什么 (z++ = y++;) 赋值无效而 (z = y) 有效?

子表达式Z++Y++两者都给出一个值。为了给子表达式赋值,你需要一个左值,你不能把一个值赋给另一个值。分配y++z++就像分配34as 3 = 4。另一方面z是一个左值,给它赋值没有问题,这就是为什么z = y是一个有效的表达式。

这个赋值 (*y++ = *z++) 是什么意思?

此分配意味着您将z指向变量的值分配给y指向然后递增的变量yz(编译器将其视为*(y++) = *(z++))。

此外,如果我运行这个程序,我会得到以下输出:
x = 0028FF04 , y = 0028FF08, z = 0028FF04 y = 0028FF04
而我的期望是
x = 0028FF04 , y = 0028FF04, z = 0028FF04 y = 0028FF08 ?

这背后的原因是声明:

printf("x=%p, y=%p, z=%p y=%p\n ", &x, y,z,y++);

其中 usingyy++together 调用未定义的行为。您正在使用具有相互依赖的副作用的表达式,但是在未定义这些副作用的应用顺序的上下文中。因此,无法保证您会得到预期的结果。

于 2013-09-08T00:49:41.130 回答
0

让我告诉你我对你的问题的理解。至于第一个

这个赋值 (*y++ = *z++) 是什么意思?

以上所有答案都给出了合理的解决方案,我不会给出第三个。

第二

此外,如果我运行这个程序,我会得到以下输出: x = 0028FF04 , y = 0028FF08, z = 0028FF04 y = 0028FF04 而我的期望是 x = 0028FF04 , y = 0028FF04, z = 0028FF04 y = 0028FF08 ?

您的期望与实际输出之间的差异是由 call-convention-of-c-function 产生的。许多c编译器默认使用cdecl-call-convention,即参数从左到右传递到堆栈中。因此,“y++”首先进入堆栈,现在您应该考虑“++”运算符的副作用。因此,“y”被传递到堆栈中,并且它被递增。而当第三个参数传入时,“y”变成了“y+1”

我不确定我是否给出了可以理解的答案,也许我犯了一些错误。欢迎您的指正。

ps:跟参数的求值顺序有关系。

于 2013-09-08T01:36:41.147 回答