C语言printf中的自增运算符

2022-05-13 14:43:20 浏览数 (1)

先看个例子:

代码语言:javascript复制
int i=1;
printf("%d====%d",  i,i  );

输出结果:3====1

是不是很意外,我开始也很意外。。。请看解析。

解析:

C语言中, i表示先运算后赋值,i 表示先赋值后运算。这个知识点相信只要会点编程的人都知道。

而C语言中,printf中自增自减运算符却有另一片天地。其实上面例子如果将C语言代码换成汇编语言,能清晰的看出来代码的执行流程,只是放出来汇编代码怕是不懂汇编的就更懵了。

所以这里我就不放汇编了,直接用最通俗的方式记录我的理解。

代码语言:javascript复制
// 在printf中,运算规则变为从右向左,输出规则为从左向右

/* 运算部分 */
// 由于运算是从右向左
i   // 由于i  是先赋值后运算,会先将1赋值,最后这个位置输出肯定是1,运算后i=2
  i    // 上一步运算后i=2,  i是先运算后赋值,所以i=3。下面开始输出

/* 输出部分 */
// 输出是从左向右
  i    // 上面已经经过运算,所以这里输出i=3
i   // 上面也说了,i  是先赋值后运算,所以这里输出为上面最初运算到这里的值i=1
    
// 所以输出3,1

PC端观看代码注释可能会更舒服一点。

再看一个例子:

代码语言:javascript复制
int i=1;
printf("%d====%d====%d",i  ,  i,  i);

解析过程:

代码语言:javascript复制
/* 运算部分,从右向左*/
  i    // 先运算后赋值,i=2=i 1
  i    // 还是先运算后赋值,i=3=i 1
i   // 先赋值后运算,所以输出i=3,再运算i=4=i 1

// 运算后的值为 i=4

/* 输出部分,从左向右*/
i   // 运算之前,i=3,所以输出3
  i    // 此时i=4,输出当前值 i=4
  i    // 此时i=4,输出当前值 i=4

其实,如果运算过程中,遇到i 这样需要先赋值后运算的情况,编译器会将运算前的值存储在寄存器中,以便在运算完成之后运行输出,所以后面输出的其实是寄存器中之前存储下来的值。

而像 i这样先运算后赋值的情况则无需寄存器来保存运算之前的值,因为运算之前的值保存下来毫无意义,它会输出运算之后的值。

i----i同理。

扩展汇编代码:

i 的汇编代码:

代码语言:javascript复制
movl -4(%rbp), �x // 将i赋值给ax寄存器, ax=5
leal 1(%rax), �x   // 将ax寄存器的值加1赋值给dx寄存器, dx=ax 1=6
movl �x, -4(%rbp) // 将dx寄存器的值赋值给i, i=dx=6

i的汇编代码:

代码语言:javascript复制
addl $1, -4(%rbp) // 将i的值增加1赋值给i, i=6

0 人点赞