C 为什么a=(b+;+;)的行为与a=b++;?
我正在用C编写一个小型测试应用程序,在我的Ubuntu 14.04上预装了GCC4.8.4。我对表达式C 为什么a=(b+;+;)的行为与a=b++;?,c,gcc,C,Gcc,我正在用C编写一个小型测试应用程序,在我的Ubuntu 14.04上预装了GCC4.8.4。我对表达式a=(b++)感到困惑的行为方式与a=b++可以。使用以下简单代码: #include <stdint.h> #include <stdio.h> int main(int argc, char* argv[]){ uint8_t a1, a2, b1=10, b2=10; a1=(b1++); a2=b2++; printf("a1=
a=(b++)感到困惑代码>的行为方式与a=b++代码>可以。使用以下简单代码:
#include <stdint.h>
#include <stdio.h>
int main(int argc, char* argv[]){
uint8_t a1, a2, b1=10, b2=10;
a1=(b1++);
a2=b2++;
printf("a1=%u, a2=%u, b1=%u, b2=%u.\n", a1, a2, b1, b2);
}
#包括
#包括
int main(int argc,char*argv[]){
uint8_t a1,a2,b1=10,b2=10;
a1=(b1++);
a2=b2++;
printf(“a1=%u,a2=%u,b1=%u,b2=%u.\n”,a1,a2,b1,b2);
}
gcc编译后的结果是a1=a2=10
,而b1=b2=11
。但是,我希望括号中的b1
在赋值给a1
之前增加
也就是说,a1
应该是11
,而a2
等于10
有人知道这个问题吗
但是,我希望括号中的b1
在赋值给a1
您不应该期望:在增量表达式周围放置括号不会改变其副作用的应用
副作用(在本例中,它意味着将11写入b1
)在检索b1
的当前值一段时间后应用。这可能发生在完整赋值表达式完全求值之前或之后。这就是为什么后置增量将保持后置增量,无论其周围是否有括号。如果需要预增量,请将++
放在变量前面:
a1 = ++b1;
将++
放在语句末尾(称为增量后),意味着增量将在语句之后执行
即使将变量括在括号中也不会改变这样一个事实,即在语句完成后,变量将递增
发件人:
在后缀形式中,增量或减量发生在值用于表达式计算之后
在前缀递增或递减操作中,递增或递减发生在值用于表达式计算之前
这就是为什么a=(b++)
和a=b++
在行为上是相同的
在您的情况下,如果您想先递增b
,您应该使用pre increment,++b
,而不是b++
或(b++)
改变
a1 = (b1++);
到
括号不会改变增量后行为本身
a1=(b1++)//b1=10
等于,
uint8_t mid_value = b1++; //10
a1 = (mid_value); //10
引用C99:6.5.2.4:
后缀++运算符的结果是操作数的值。
获得结果后,操作数的值将递增。
(即,将适当类型的值1添加到其中。)请参阅
关于可加算子和复合赋值的讨论
有关约束、类型和转换以及
指针上的操作。更新存储值的副作用
在上一个序列和下一个序列之间应发生操作数的变化
重点
您可以查阅C99:附录C以了解有效序列点是什么
在你的问题中,仅仅添加括号并不会改变序列点,只有代码>角色就是这样做的
或者换句话说,您可以将其视为b
的临时副本,并且副作用是原始b
递增的。但是,在到达序列点之前,所有计算都在b
的临时副本上进行。然后丢弃b
的临时副本,当到达序列点时,副作用即增量操作被提交到存储器。括号可能很难考虑。但他们的意思是“确保里面的一切先发生”
假设我们有
a = b + c * d;
乘法高于加法的优先级告诉我们,编译器将安排将c乘以d,然后将结果加到b。如果需要其他解释,可以使用括号:
a = (b + c) * d;
a = 2*b+1;
但是假设我们在混合中加入了一些函数调用。也就是说,假设我们写作
a = x() + y() * z();
现在,虽然很清楚y()的返回值将乘以z()的返回值,但我们可以谈谈x()、y()和z()的调用顺序吗?答案是,不,我们绝对不能!如果您有任何不确定的地方,我邀请您尝试使用以下x、y和z函数:
int x() { printf("this is x()\n"); return 2; }
int y() { printf("this is y()\n"); return 3; }
int z() { printf("this is z()\n"); return 4; }
我第一次尝试这个方法时,使用面前的编译器,我发现函数x()是先调用的,尽管它的结果是最后才需要的。当我把呼叫代码改为
a = (x() + y()) * z();
对x、y和z的调用顺序保持完全相同,编译器只是安排以不同的方式组合它们的结果
最后,重要的是要认识到像i++
这样的表达式做两件事:它们获取i
的值并向其中添加1,然后将新值存储回i
。但是存储回i
不一定马上发生,它可以在以后发生。“存储回到i
的确切时间是什么时候?”这一问题类似于“函数x什么时候被调用?”。你真的不知道,这取决于编译器,这通常无关紧要,不同的编译器会有所不同,如果你真的在意,你将不得不做一些其他事情来强制顺序
在任何情况下,请记住i++
的定义是,它将i
的旧值提供给周围的表达式。这是一个非常绝对的规则,不能仅仅通过添加一些括号来改变它!括号不是这样的
让我们回到前面的例子,其中涉及函数x、y和z。我注意到函数x首先被调用。假设我不想这样,假设我想先调用函数y和z。我能做到吗
x = z() + ((y() * z())?
c = y();
d = z();
b = x();
a = b + c * d;
c = b++;
a = b;
a = ++b;
a = 2*(b+1);
a = 2*b+1;
= =
/ \ / \
a * a +
/ \ / \
2 + * 1
/ \ / \
b 1 2 b
a = 2*(b+1); a = 2*b+1;
a1 = (b1++);
a2 = b2++;
=
/ \
a ++ (postfix)
|
b
#include <iostream>
using namespace std;
int b;
struct verbose
{
int x;
void operator=(int y) {
cout << "b is " << b << " when operator= is executed" << endl;
x = y;
}
};
int main() {
// your code goes here
verbose a;
b = 10;
a = b++;
cout << "a is " << a.x << endl;
return 0;
}
b is 11 when operator= is executed
a is 10