c++ - C语言 关于b=a+++a++运算问题?
阿神
阿神 2017-04-17 14:00:29
0
17
2788

篇幅有点长,让您受累了。。。

a++这个问题一直很困扰,自己做了个测试,虽然都知道a++是先使用

a再进行自加,疑问点就是这个a使用的期限是什么时候结束?一开始以为是表达式代码行完成后,在第二行代码需要试用a时,就是自加结果,这也是最常用的情况,也很好理解,如:

int a=0,b;
b=a++;
printf("a=%d b=%d",a,b);//输出:a=1,b=0

那假如在同一行表达式中出现2次a++,也就是说a++后又与其他变量进行运算,如下代码:

int a=10,b=0;
b=a+++a++;
printf("a=%d b=%d",a,b);//输出a=12 b=21

如果上面的理论成立那b应该等于20,根据执行结果显然不成立,所以我觉得应该是当执行a++运算时,a还是10,但当a在与其他变量继续运算时a就已经完成了自增,就是自增后的值与其他变量运算了,在变下代码再测试:

int a=10,b=0;
b=a+++b;//b=10(因为a++优先级大于++b,所以直观点应该是b=(a++)+b,尽管此时括号是多余的)

显然这种说法也不成立。

对b=a+++a++运算的猜测步骤为:

  1. 第一个a++ //此时a=10

  2. 第二个a++ //因为第一步运算完后a自增1,所以此时a=11,是第一个a++运算后的值

  3. b=a+a //b=11+11=22,这点就不理解了,之所以最终结果这个b=21,难道是b=10+11吗,但中间+号的表达式两端都是a,应该两端的值都是一样的啊,应是22或20啊,怎么会是21,b=(a++)+(++a) 这个结果为22,应该可以说明+号两边都是a的话,第一个表达式a++中a会被++a后的值覆盖,所以b=11+11。

求解释b=a++a++的详细运算步骤,为啥会是b=21?

还有个问题:

int i=1;
int j=0;
for(;j<5;j++){
     i=i++;
     printf("i=%d",i);
}
printf("i=%d",i);

为什么i=1?为什么i=i++执行完后,在执行j<5之前或在下一轮执行前i没有自加?及时for循环中i=1,那for循环执行完后i应该至少会加1吧,起码i也得等于2啊?

阿神
阿神

闭关修行中......

reply all(17)
PHPzhong

First of all, in fact, it has been clearly stated above that writing such code is very irresponsible. But since we want to discuss it, let’s discuss this issue in a discussion way. The code I tested is not complicated, just the following lines:

#include <stdio.h>
int main()
{
    int a=0,b=0;
    a = 10;
    b = a+++a++;
    printf("%d %d\n", b, a);
    return 0;
}

Compiler: gcc version 4.9.2 (Raspbian 4.9.2-10)
Output result:

21 12

Let’s first discuss the equivalent situation of a+++a++. According to the C language operator priority, postfix ++ has a higher priority than +, that is, a+++a++ can in principle be equivalent to (a++)+(a++). So, how does the compiler understand it? It understands it as a syntax tree, something like this:

        +
       / \
      /   \
    a++   a++
After , how does the compiler handle it? stack-based operations generally look like this:

  • 1. Process the first

    a++ operation: Because it is a post-position operation, a (at this time a=10) is pushed onto the stack, and then a=a+1, now a is 11;

  • 2. Process the second

    a++ operation: the same, first push a (at this time a=11) onto the stack, and then a= a+1, now a is 12;

  • 3. Process the

    + (sum) operation: Because + is a binary operation (that is, an operation that requires two operands), first pop the two operands from the stack, That is, 10 and 11 just pushed onto the stack, and then do the + operation, that is, 10+11, and the final result is 21.

The basic description is:

  • push(a), a onto stack(10)

  • a=a+1, a plus 1

  • push(a), a onto stack(11)

  • a=a+1, a plus 1

  • b=pop()+pop(), add the two operands (10,11) from the stack and assign the value to b(=21)

In the stack-based processing method, the operands are popped from the stack and then operated (of course, the data in the stack was also pushed in before), instead of directly using a to calculate, modern compilers are basically implemented based on the stack method. I guess this is where your doubts lie. If you want to know more, you can read about Compilation Principles.

According to the general practice of compilers, the above steps should be the same. There may be some differences after enabling optimization. I saw someone saying

(a++)+(a++) In gcc4.5.1, I finally got 20. In my hand There is no 4.5.1, but 21 is obtained on 4.9.2 and 4.2.1, and different optimization levels have been tried. If true, it may be other options or a problem between versions.

Finally, I have not studied the principles of compilation in depth, so I can only give a rough idea. Not all compilers use the stack method to solve expressions. Please correct me if there are any mistakes.

As I said before, try to write code that is easy for people to understand.

阿神

If you test it with different compilers, you will find that the results are different from your current results. Or if you change the compilation parameters under the same compiler, the results will be different. In the final analysis, this type of problem is undefined behavior. Therefore, what you have to remember is not when i will be added, but to ensure that you do not write such garbage code. .

洪涛

The questioner can take a look at this
[] (https://en.m.wikipedia.org/wiki/Undefined_behavior)
Construct the same object between two sequence points Two modifications are undefined behavior and unpredictable

Peter_Zhu

standard C is not defined
The compiler handles it by itself according to its own rules.

大家讲道理

Teacher Qiu Zongyan has already given a complete answer to this question.

Back to the previous example: "Who knows what value is assigned to n in the following C statement?"

m = 1; n = m++ +m++;

The correct answer is: I don’t know! The language does not specify what it should calculate, and the results completely depend on the specific processing of the specific system in the specific context. This involves the order of evaluation of the operands and the implementation time of variable modification.

http://www.math.pku.edu.cn/teachers/qiuzy/technotes/expression2009.pdf

阿神

Undefined behavior.

Compiler implementations are different because ++ has an impact, and the time at which the compiler eliminates the impact is different.

Peter_Zhu

This kind of question makes no sense. This kind of statement cannot appear in your code at all

迷茫

I remembered an article I read before, which is similar to your question.
Link

No matter what, it is best to use concise and easy-to-understand statements as much as possible in the project, and avoid such code that does not know what strange problems will occur.

刘奇

First of all, I admire the author’s spirit of exploration.
But I suggest you take a look:

  1. Priority of C language operators

  2. Associativity of C language operators

As if that’s not enough, let’s take a look at the detailed semantic description of the relevant operators in the C language specification:

http://eli-project.sourceforge.net/c_html/c.html

It doesn’t seem to work, so we can only look at the implementation of the compiler.

PHPzhong

This seems to be related to the compiler. In fact, when you understand it, you can understand it like this: i++ => b = i; i = i + 1; and then the return value of I++ is b, so you can understand it this way. Some compilers return i, then i = i + 1;

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template