printf中的自增运算符

前言

文中均设i=5,汇编代码:movl $5, -4(%rbp) // 将5赋值给rdp向下偏移4个指针的头指针(i)
在装用gcc环境的PC下,可以使用gcc -S -o assembly.S yourcodefile.c 打印汇编代码。首先打印出简单自增运算的汇编代码:

i++; 的汇编代码

在早版本的编译器中可能是如下表达形式,而在最新版的gcc中,i++;++i;的汇编代码是一样的。

movl -4(%rbp), %eax // 将i赋值给ax寄存器, ax=5
leal 1(%rax), %edx   // 将ax寄存器的值加1赋值给dx寄存器, dx=ax+1=6
movl %edx, -4(%rbp) // 将dx寄存器的值赋值给i, i=dx=6

++i; 的汇编代码

addl $1, -4(%rbp)    // 将i的值增加1赋值给i, i=6

printf函数的自增运算符

printf("%d",i++);

通过拓展i++;的早期汇编代码,可以推出printf("$d",i++);的汇编代码如下所示:

movl -4(%rbp), %eax // 将i赋值给ax寄存器, ax=5
leal 1(%rax), %edx  // 将ax寄存器的值加1赋值给dx寄存器, dx=ax+1=6
movl %edx, -4(%rbp) // 将dx寄存器的值赋值给i, i=dx=6
movl %eax, %edx     // 将ax寄存器的值赋值给dx寄存器, dx=ax=5
call _printf                 // 调用printf函数,打印dx寄存器的值5

不难发现,在进行自增运算操作之前,i的原始值5已经被提前存入寄存器ax中,进行完自增操作后,从ax寄存器中取出i的原始值

printf("%d",++i);

通过拓展++i;的汇编代码,可以推出printf("$d",++i);如下所示:

addl $1, -4(%rbp)       // 将i的值增加1赋值给i, i=6
movl -4(%rbp), %eax // 将i赋值给ax寄存器, ax=6
movl %eax, %edx      // 将ax寄存器的值赋值给dx寄存器, dx=ax=6
call _printf                  // 调用printf函数,打印dx寄存器的值6

printf("$d",i++);相比,主要是movl -4(%rbp), %eax所在的位置不一致,这是由本身的性质决定的

printf("%d %d",i++,++i)

结合i++;++i;的汇编代码,可以推出printf("%d%d",i++,++i)的汇编代码如下所示:

/*++i part1 begin*/
addl $1, -4(%rbp)       // 将i的值增加1赋值给i, i=6
/*++i part1 end*/

/*i++ begin*/
movl -4(%rbp), %eax // 将i赋值给ax寄存器, ax=6
leal 1(%rax), %edx  // 将ax寄存器的值加1赋值给dx寄存器, dx=ax+1=7
movl %edx, -4(%rbp) // 将dx寄存器的值赋值给i, i=dx=7
/*i++ end*/

/*++i part2 begin*/
movl -4(%rbp), %edx // 将i赋值给dx寄存器, ax=7
/*++i part2 end*/

movl %edx, %ecx      // 把7赋值给cx寄存器
movl %eax, %edx     // 把6赋值给dx寄存器
call _printf                 // 调用printf函数,打印dx、cx寄存器

可见printf("%d %d",i++,++i)的输出是6 7

printf("%d %d",i++,i++)

结合i++;++i;的汇编代码,可以推出printf("%d%d",i++,++i)的汇编代码如下所示:

/*2nd i++ begin*/
movl -4(%rbp), %edx // 将i赋值给ax寄存器, dx=5
leal 1(%rdx), %eax  // 将dx寄存器的值加1赋值给ax寄存器, ax=dx+1=6
movl %eax, -4(%rbp) // 将ax寄存器的值赋值给i, i=ax=6
/*2nd i++ end*/

/*1st i++ begin*/
movl -4(%rbp), %eax // 将i赋值给ax寄存器, ax=i=6
leal 1(%rax), %ecx  // 将ax寄存器的值加1赋值给cx寄存器, cx=ax+1=7
movl %ecx, -4(%rbp) // 将cx寄存器的值赋值给i, i=cx=7
/*1st i++ end*/

movl %edx, %ecx      // 把5赋值给cx寄存器
movl %eax, %edx     // 把6赋值给dx寄存器
call _printf                 // 调用printf函数,打印dx、cx寄存器

可见printf("%d %d",i++,++i)的输出是6 5

printf("%d %d %d",i++,++i,i++)

结合i++;++i;的汇编代码,可以推出printf("%d %d",i++,++i,i++)的汇编代码如下所示:

/*2nd i++ begin*/
movl -4(%rbp), %edx // 将i赋值给ax寄存器, dx=5
leal 1(%rdx), %eax  // 将dx寄存器的值加1赋值给ax寄存器, ax=dx+1=6
movl %eax, -4(%rbp) // 将ax寄存器的值赋值给i, i=ax=6
/*2nd i++ end*/

/*++i part1 begin*/
addl $1, -4(%rbp)       // 将i的值增加1赋值给i, i=7
/*++i part1 end*/

/*1st i++ begin*/
movl -4(%rbp), %eax // 将i赋值给ax寄存器, ax=i=7
leal 1(%rax), %ecx  // 将ax寄存器的值加1赋值给cx寄存器, cx=ax+1=8
movl %ecx, -4(%rbp) // 将cx寄存器的值赋值给i, i=cx=8
/*1st i++ end*/

/*++i part2 begin*/
movl -4(%rbp), %ecx // 将i赋值给cx寄存器, cx=8
/*++i part2 end*/

movl %edx, %n      // 把5赋值给n寄存器
movl %ecx, %n2      // 把8赋值给n2寄存器
movl %eax, %edx     // 把7赋值给dx寄存器
call _printf                 // 调用printf函数,打印dx、n2、n寄存器

可见printf("%d %d %d",i++,++i,i++)的输出是7 8 5,那么printf("%d %d",++i,++i)的输出是7 7printf("%d %d",++i,i++)的输出是7 5

原文地址:https://www.cnblogs.com/shy-/p/11874621.html

时间: 2024-10-17 04:37:14

printf中的自增运算符的相关文章

算术运算符中的自增与自减的注意事项

++.--两种运算符都是单目运算符,具有向右结合性(也就是优先与运算符右边的变量结合),而且他们的优先级比其他算术运算符高.当++或--运算符置于变量的左边时,称为前置运算,表示先进行自增或自减运算再使用变量的值,而当++或--运算符置于变量的右边时,称为后置运算,表示先引用变量的值再自增或自减运算. 如,设i=1,j=2,则在计算++i+j--的结果时,先进行++i运算,得i=2,再进行j--运算,根据后置运算规则可知,系统将先引用j的原始值2与i的新值2相加,之后再进行j--,得j=1.因此

C语言杂谈(二)自增运算符++与间接访问运算符*的结合关系和应用模式

自增运算符++有前缀和后缀两种,在搭配间接访问运算符*时,因为顺序.括号和结合关系的影响,很容易让人产生误解,产生错误的结果,这篇文章来详细分析一下这几种运算符的不同搭配情况. ++.--和*的优先级顺序 在C语言运算符的优先级顺序中,后缀的++和--运算符运算优先级16,结合关系是从左到右:简介访问运算符*.前缀++和--运算符运算优先级15,结合关系是从右到左.根据这个关系,可以分析出不同情况下的应用.为了更直观的体现,有以下的例子. 举例说明 有数组a[5],值分别为10,11,12,13

*p++与(*p)++与*(p++)------自增运算符常见误区

自增运算符(++) 自增\自减运算符分为前缀形(++a)和后缀形(a++),这里重点分析自增 大部分人对前缀和后缀的理解一般是,前缀形式是先++再使用(先变后用),后缀形式是先使用再++(先用后变)   (tips:自增运算符只能作用于变量,而不能作用于变量或表达式,例:(i+j)++就是非法的) 先来说一下一般情况 1 main() 2 { 3 int a = 3; 4 int b; 5 6 b = a++; 7 printf("%d", b); 8 } 上面这种应该大部分人都会,属

一个由自增运算符以及C语法顺序细节引起的bug

 一.问题描述 在编写modbus代码时发生一件由语法细节引起的bug,起因是自增运算符以及C语法顺序. 输入的数据是2233=0X08B9,高低字节顺序是0x08 0xB9, 使用modbus poll向92寄存器写入十进制数据2233. 但是经过(*reg++)*256+(reg++)之后,结果变成了0xB908. 检查内存也是0xB908. 说明reg_value写入了错误的数. 二.问题调查 反汇编后查看. 1)LDRB R2,[R5],#0X01 --> 把R5数据的低字节放入R2,并

Java中的自增操作符与中间缓存变量机制

转自:http://blog.csdn.net/maggiedorami/article/details/7986098 我们来看这样一段程序: public static void main(String[] args){ int i, sum1, sum2; i=0; sum1 = (i++)+(i++); System.out.println("sum1="+sum1); i = 0; sum2 = (++i)+(++i); System.out.println("su

C#自增运算符(++)

一.C#自增运算符(++) 自增运算符(++)是将操作数加1. 1. 前缀自增运算符 前缀自增运算符是“先加1,后使用”.它的运算结果是操作数加1之后的值. 例如: ++x;  // 前缀自增运算符 2. 后缀自增运算符后缀自增运算符是“先使用,后加1”.它的运算结果是操作数加1之前的值. 例如: x++;  // 后缀自增运算符 二.提示 自增运算符(++)适用于数值和枚举类型. 三.示例 using System;using System.Collections.Generic;using

C++重载自增运算符的效率问题

C++规定后缀形式有一个int类型参数,当函数被调用时,编译器传递一个0做为int参数的值给该函数. increment的前缀形式表示“增加然后取回”,后缀形式表示“取回然后增加”. 1 #include "stdafx.h" 2 #include "assert.h" 3 class A 4 { 5 public: 6 A(int i) 7 :m_i(i) 8 { 9 } 10 // ++i 11 A& operator++() 12 { 13 ++m_i

自增运算符

// // main.c // c自增运算符 // // Created by mac on 2019/4/9. // Copyright ? 2019年 mac. All rights reserved. // #include <stdio.h> int main(int argc, const char * argv[]) { int count=1; count++; count=5; int i=8; int y,b=3; y=(++b)+(b++);//8 printf("

python中基本数据类型以及运算符

python中基本数据类型以及运算符的知识 一.与用户的交互以及python2与python的区别 1.1什么是与用户交互 用户交互就是人往计算机中input(输入数据),计算机print(输出结果),用户交互的本质就是输入输出. 1.2输入input username = input("请输入您的姓名: ")>>请输入您的姓名: 占亚峰password = input('请输入您的密码: ')>>请输入您的密码: 123456 1.3输出print print