Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么a=(b+;+;)的行为与a=b++;?_C_Gcc - Fatal编程技术网

C 为什么a=(b+;+;)的行为与a=b++;?

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=

我正在用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=%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