1

Summary

1) ++ and - participate in the mixed operation result is uncertain, such as r = (i++) + (i++); etc.

  • C++ only specifies the relative execution order corresponding to ++ and - (the value and auto-increment)
  • ++ and - The assembly instructions corresponding to
  • In the mixed operation, the assembly instruction of ++ and - may be interrupted (the value and auto-increment may be interrupted, and other codes are inserted in the middle)

2) The greedy method of the

  • The compiler as many characters as possible from left to right, one by one 16176b873dc766
  • When the read character cannot form a legal symbol with the already read character

3) The space can be used as the rest of a complete symbol of compiler reads the space, it will immediately process the previously read symbol.

Analysis of ++ and - Operator

1、Demo1

  • What is the output of the following code?

    int i = 0;
    int r = 0;
    
    r = (i++) + (i++) + (i++);
    printf("i = %d\n, r = %d\n", i, r);
    
    r = (++i) + (++i) + (++i);
    printf("i = %d\n, r = %d\n", i, r);
  • Preliminary analysis of the code:

    第一行输出:i = 3, r = 3;    // 按照从左向右的计算方法,i先取值,再自增,
                                // 则r = 0 + 1 + 2 = 3;
    第二行输出:i = 6, r = 16;   // 同上,r = 4 + 5 + 6 = 15;

The actual output of the above code in the VS2015 compiler is:

i = 3, r = 0;
i = 6, r = 18;

View the disassembly result with the help of the Vs compiler:
image.png
Code analysis:

对于r = (i++) + (i++) + (i++);    // 先取了i的值做了相加,赋值给r;然后i自增3次
    在汇编层面,做的操作依次是:
    1)00C542BC mov 将i代表的这个地址中的值放到寄存器eax中,为0
    2)00C542BF add eax的值和i的值累加,累加和仍然为0
    3)00C542C5 mov 将eax里的值放到r变量代表的内存里,
            所以r的值为0
    4)后面做了3次相同的操作:将i变量内存里的值放到ecx寄存器里,然后加1,
       再把ecx里的值放回i变量的内存里;重复2次
            所以i的值为3

对于r = (i++) + (i++) + (i++);    // 先给i自增了3次;然后把i的值加3次给了r
    在汇编层面,做的操作依次是:
    1)009A42F8 到 009A42FE 将i代表的这个地址中的值放到寄存器eax中;
                            然后eax里的值自增1;
                            写回i的内存里,此时i的值为4
                            重复2次后,i的值为6
            所以i的值为6
    2)009A4313 mov 把i里的值移动到eax寄存器中,eax里的值为6
    3)009A4316 add eax里的值加上i的值,即6+6,eax里的值为12
    4)009A4319 add eax里的值加上i的值,即12+6,eax里的值为18
    5)009A4319 mov eax里的值写回r代表的内存里
            所以r的值为18
                            

This piece of code, our analysis and the actual compiler results are very different; then what about other compilers?
bcc compiler and the vc compiler are the same, while gcc compiler are "r = 0 and r = 16"

The output result of the above code in the java compiler:

// test.java
public static void main(String[] args) {
    System.out.println("test.java file name must be equal to the class name test");
    int i = 0;
    int r = 0;
    
    r = (i++) + (i++) + (i++);
    System.out.println("i = " + i + ", r = " + r);

    r = (++i) + (++i) + (++i);
    System.out.println("i = " + i + ", r = " + r);
}

// 编译:javac test.java
// 执行:java test
// 输出:i = 3, r = 3
        i = 6, r = 15   和分析的一致

The above test description: ++ and - participate in the mixed operation result is uncertain

  • C++ only specifies the relative execution order of ++ and-corresponding instructions
  • ++ and-the corresponding assembly instructions are not necessarily executed continuously
  • In mixed operations, the assembly instructions of ++ and - may be interrupted in execution

2、Demo2

  • What is the output of the following code?

    int i = 0;
    int j = ++i+++i+++i;
    
    int a = 1;
    int b = 4;
    int c = a+++b;
    
    int* p = &a;
    b = b/*p;   
    
    printf("i = %d\n", i);
    printf("j = %d\n", j);
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    printf("c = %d\n", c);

compiler's greedy method

  • The compiler as many characters as possible one by one from left to right
  • When the read character cannot form a legal symbol with the character that has been read

Code analysis:

int j = ++i+++i+++i;    
    // 编译器先读到1个'+',不知道啥意思;
    // 继续读到1个'+',它觉得这是个前置的'++'
    // 然后读到了i,确定了这是个'++i'表达式
    // 继续读到1个'+',这可能是一个加法的运算符 '+'
    // 继续读到1个'+',这时候判断是一个后置的 '++',后面再读任何数都不对了,读到变量,不合法;读到符号,也不对;
    // 这时候编译器就停止处理了,所以编译器就得到了 “++i++”
    // 然后计算得到了 “1++”,对一个右值1进行自增,自然会编译错误!

int c = a+++b;
    // 编译器依次读了3个字符'a++',知道这是个后置的++
    // 然后读到了1个'+',觉得这个可能是个加法运算符
    // 继续读到了b,后面也没有其他字符了,所以得到了 (a++) + b
    // 计算得到了c = 5

b = b/*p;    // error,编译器会将/*识别为注释,因此整个程序会编译失败
// 如果愿意是用b的值除以*p的值,那么就应该用括号或者空格表明
b = b / (*p); 或 b = b / *p; 

This article is summarized from "C Language Advanced Course" by Tang Zuolin from "Ditai Software Academy".
If there are any errors or omissions, please correct me .


bryson
169 声望12 粉丝