爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      C语言反汇编 - 数据类型与常量

      首页 知识中心 软件开发 文章详情页

      C语言反汇编 - 数据类型与常量

      2024-07-30 09:33:29 阅读次数:33

      C语言,编程开发

      反汇编(Disassembly) 即把目标二进制机器码转为汇编代码的过程,该技术常用于软件破解、外挂技术、病毒分析、逆向工程、软件汉化等领域,学习和理解反汇编对软件调试、系统漏洞挖掘、内核原理及理解高级语言代码都有相当大的帮助,软件一切神秘的运行机制全在反汇编代码里面。

      寻找OEP

      1.使用编译器 VS 2013 Express 版本,写代码,并关闭基地址随机化,编译采用debug版。

      C语言反汇编 - 数据类型与常量

      2.寻找OEP,x64dbg 载入,默认停在,回车跟进。

      C语言反汇编 - 数据类型与常量

      call <__tmainCRTStartup> 再次回车跟进。

      C语言反汇编 - 数据类型与常量

      下方看到一个安全cookie检测,主要防止在目标堆栈中瞎搞,而设计的安全机制。编译器开启后,每次运行都会生成随机cookie,结束时会验证是否一致,防止瞎搞,老版本编译器中不存在这个选项,一开始开发人员也没想那么多,后来瞎搞的人多了,才加上的,主要是害怕自己的windows被玩坏。

      C语言反汇编 - 数据类型与常量

      继续向下看代码,看到以下代码就到家了,call 0x0041113B 跟进去就是main.

      C语言反汇编 - 数据类型与常量

       

      数值类型变量: 数值类型默认在32位编译器上是4字节存储的。

      #include <stdio.h>
      
      int main(int argc, char* argv[])
      {
      	int x = 10, y = 20, z = 0;
      	printf("%d\n", x + y);
      	return 0;
      }
      

      反汇编结果如下,如果在vc6下mov ecx,0xC 原因 int=4 3*4=0xC

      004113CC | 8DBD 1CFFFFFF            | lea edi,dword ptr ss:[ebp-0xE4]                | 取出内存地址
      004113D2 | B9 39000000              | mov ecx,0x39                                   | 指定要填充的字节数
      004113D7 | B8 CCCCCCCC              | mov eax,0xCCCCCCCC                             | 将内存填充为0xcccccc
      004113DC | F3:AB                    | rep stosd                                      | 调用rep指令,对内存进行初始化
      004113DE | C745 F8 0A000000         | mov dword ptr ss:[ebp-0x8],0xA                 | 对变量x初始化为10
      004113E5 | C745 EC 14000000         | mov dword ptr ss:[ebp-0x14],0x14               | 对变量y初始化为20
      004113EC | C745 E0 00000000         | mov dword ptr ss:[ebp-0x20],0x0                | 对变量c初始化为0
      004113F3 | 8B45 F8                  | mov eax,dword ptr ss:[ebp-0x8]                 | 取出10并放入eax
      004113F6 | 0345 EC                  | add eax,dword ptr ss:[ebp-0x14]                | 与20相加得到结果付给eax
      004113F9 | 8BF4                     | mov esi,esp                                    | 保存当前栈帧
      004113FB | 50                       | push eax                                       |
      004113FC | 68 58584100              | push consoleapplication1.415858                | 415858:"%d\n"
      00411401 | FF15 14914100            | call dword ptr ds:[<&printf>]                  |
      00411407 | 83C4 08                  | add esp,0x8                                    |
      

      除了整数类型外,浮点数也是一种数值运算方式,将上方代码稍微修改后,编译并查看其反汇编代码.

      #include <stdio.h>
      
      int main(int argc, char* argv[])
      {
      	double x = 1.05, y = 20.56, z = 0;
      	z = x + y;
      	printf("%f\n", z);
      	return 0;
      }
      

      观察以下汇编代码,会发现前面的初始化部分完全一致,但后面则使用了xmm0寄存器,该寄存器是专门用于运算浮点数而设计的浮点运算模块默认大小就是64位,其将内存中的值取出来并放入xmm0中进行中转,然后复制到堆栈中,等待最后调用addsd命令完成对浮点数的加法运算,并将运算结果回写到缓冲区,最后调用打印函数实现输出.

      004113CC | 8DBD 10FFFFFF            | lea edi,dword ptr ss:[ebp-0xF0]                          |
      004113D2 | B9 3C000000              | mov ecx,0x3C                                             |
      004113D7 | B8 CCCCCCCC              | mov eax,0xCCCCCCCC                                       |
      004113DC | F3:AB                    | rep stosd                                                |
      004113DE | F2:0F1005 70584100       | movsd xmm0,qword ptr ds:[<__real@3ff0cccccccccccd>]      | 将内存地址中的值取出并放入xmm0中
      004113E6 | F2:0F1145 F4             | movsd qword ptr ss:[ebp-0xC],xmm0                        | 将数据放入堆栈中存储
      004113EB | F2:0F1005 80584100       | movsd xmm0,qword ptr ds:[<__real@40348f5c28f5c28f>]      |
      004113F3 | F2:0F1145 E4             | movsd qword ptr ss:[ebp-0x1C],xmm0                       |
      004113F8 | F2:0F1005 60584100       | movsd xmm0,qword ptr ds:[<__real@0000000000000000>]      |
      00411400 | F2:0F1145 D4             | movsd qword ptr ss:[ebp-0x2C],xmm0                       |
      00411405 | F2:0F1045 F4             | movsd xmm0,qword ptr ss:[ebp-0xC]                        | main.c:6
      0041140A | F2:0F5845 E4             | addsd xmm0,qword ptr ss:[ebp-0x1C]                       | 对浮点数进行相加操作
      0041140F | F2:0F1145 D4             | movsd qword ptr ss:[ebp-0x2C],xmm0                       | 结果放入堆栈等待被打印
      00411414 | 8BF4                     | mov esi,esp                                              |
      00411416 | 83EC 08                  | sub esp,0x8                                              |
      00411419 | F2:0F1045 D4             | movsd xmm0,qword ptr ss:[ebp-0x2C]                       |
      0041141E | F2:0F110424              | movsd qword ptr ss:[esp],xmm0                            |
      00411423 | 68 58584100              | push consoleapplication1.415858                          | 415858:"%f\n"==L"春\n"
      00411428 | FF15 14914100            | call dword ptr ds:[<&printf>]                            |
      0041142E | 83C4 0C                  | add esp,0xC                                              |
      

      C语言反汇编 - 数据类型与常量

      字符与字符串变量:

      #include <stdio.h>
      
      int main(int argc, char* argv[])
      {
      	char x = 'a', y = 'b',z = 'c';
      	printf("x = %d --> y = %d --> z = %d", x,y,z);
      	return 0;
      }
      

      反汇编结果如下,观察发现字符型的表现形式与整数类型基本一致,只是在数据位大小方面有所区别,如上int类型使用dword作为存储单位,而字符类型则默认使用byte形式存储。

      004113CC | 8DBD 1CFFFFFF            | lea edi,dword ptr ss:[ebp-0xE4]          |
      004113D2 | B9 39000000              | mov ecx,0x39                             |  
      004113D7 | B8 CCCCCCCC              | mov eax,0xCCCCCCCC                       |  
      004113DC | F3:AB                    | rep stosd                                |
      004113DE | C645 FB 61               | mov byte ptr ss:[ebp-0x5],0x61           | 第一个字符
      004113E2 | C645 EF 62               | mov byte ptr ss:[ebp-0x11],0x62          | 第二个字符
      004113E6 | C645 E3 63               | mov byte ptr ss:[ebp-0x1D],0x63          | 第三个字符
      004113EA | 0FBE45 E3                | movsx eax,byte ptr ss:[ebp-0x1D]         | 拷贝第三个字符
      004113EE | 8BF4                     | mov esi,esp                              | esi:__enc$textbss$end+109
      004113F0 | 50                       | push eax                                 |
      004113F1 | 0FBE4D EF                | movsx ecx,byte ptr ss:[ebp-0x11]         | 拷贝第二个字符
      004113F5 | 51                       | push ecx                                 |
      004113F6 | 0FBE55 FB                | movsx edx,byte ptr ss:[ebp-0x5]          | 拷贝第一个字符
      004113FA | 52                       | push edx                                 |
      004113FB | 68 58584100              | push consoleapplication1.415858          | 415858:"x = %d --> y = %d --> z = %d"
      00411400 | FF15 14914100            | call dword ptr ds:[<&printf>]            | 打印输出
      00411406 | 83C4 10                  | add esp,0x10                             |
      

      虽然使用的是byte存储一个字符,但是每一个字符在分配上还是占用了12个字节的空间4x3=12,编译器并没有因为它是一个字符而区别对待,同样是采用了4字节的分配风格.

      C语言反汇编 - 数据类型与常量

      反汇编第一种形式的字符串类型,发现首先会从常量字符串中ds:[0x415858]取出前四个字节子串,并将其压入堆栈中,然后再循环后四个字节子串并压栈,最后取出第一个字符串的堆栈地址并输出打印,该方法只适用于小字符串.

      004113E8 | A1 58584100              | mov eax,dword ptr ds:[0x415858]         | 在常量字符串中取出数据 "hell"
      004113ED | 8945 E8                  | mov dword ptr ss:[ebp-0x18],eax         | 将常量前面的hell压栈
      004113F0 | 8B0D 5C584100            | mov ecx,dword ptr ds:[0x41585C]         | 继续压栈 "o lyshark"
      004113F6 | 894D EC                  | mov dword ptr ss:[ebp-0x14],ecx         |
      004113F9 | 8B15 60584100            | mov edx,dword ptr ds:[0x415860]         | 00415860:"shark"
      004113FF | 8955 F0                  | mov dword ptr ss:[ebp-0x10],edx         |
      00411402 | 66:A1 64584100           | mov ax,word ptr ds:[0x415864]           | 00415864:L"k"
      00411408 | 66:8945 F4               | mov word ptr ss:[ebp-0xC],ax            | 最后将剩下的一个字单位压栈
      0041140C | 8BF4                     | mov esi,esp                             | main.c:8
      0041140E | 8D45 E8                  | lea eax,dword ptr ss:[ebp-0x18]         | 取出hell的内存地址作为首地址使用
      00411411 | 50                       | push eax                                |
      00411412 | 68 68584100              | push consoleapplication1.415868         | 415868:"短字符串: %s\n"
      00411417 | FF15 14914100            | call dword ptr ds:[<&printf>]           | 打印输出
      0041141D | 83C4 08                  | add esp,0x8                             |
      

      C语言反汇编 - 数据类型与常量

      反汇编长字符串与字符串指针,由于这两个类型具有很强的对比性所以放在一起,第1种字符串数组存储,可以看到内部是通过拷贝内存实现的,而第2种指针方式则是直接引用常量地址,从效率上来说指针效率更高,因为没有拷贝造成的性能损失.

      004113E5 | 8945 FC                  | mov dword ptr ss:[ebp-0x4],eax          |
      004113E8 | B9 06000000              | mov ecx,0x6                             | 循环拷贝6次
      004113ED | BE 58584100              | mov esi,0x415858                        | 字符串常量地址
      004113F2 | 8D7D DC                  | lea edi,dword ptr ss:[ebp-0x24]         | 取出初始化的内存空间首地址
      004113F5 | F3:A5                    | rep movsd                               | 循环拷贝6次
      004113F7 | 66:A5                    | movsw                                   | 单独拷贝最后的y字符
      
      004113F9 | C745 D0 78584100         | mov dword ptr ss:[ebp-0x30],0x415858    | 取字符串常量地址
      00411400 | 8BF4                     | mov esi,esp                             | main.c:8
      00411402 | 8D45 DC                  | lea eax,dword ptr ss:[ebp-0x24]         | 通过指针指向字符串首地址
      00411405 | 50                       | push eax                                |
      
      00411406 | 68 98584100              | push consoleapplication1.415898         | 415898:"长字符串: %s\n"
      0041140B | FF15 14914100            | call dword ptr ds:[<&printf>]           |
      00411411 | 83C4 08                  | add esp,0x8                             |
      00411414 | 3BF4                     | cmp esi,esp                             |
      00411416 | E8 1BFDFFFF              | call 0x411136                           | 此处忽略,堆栈检测仪
      0041141B | 8BF4                     | mov esi,esp                             | main.c:9
      
      0041141D | 8B45 D0                  | mov eax,dword ptr ss:[ebp-0x30]         | 取地址直接打印常量
      00411420 | 50                       | push eax                                |
      00411421 | 68 A8584100              | push consoleapplication1.4158A8         | 4158A8:"字符串指针: %s\n"
      00411426 | FF15 14914100            | call dword ptr ds:[<&printf>]           |
      0041142C | 83C4 08                  | add esp,0x8                             |
      

      C语言反汇编 - 数据类型与常量

      常量折叠/常量传播: 在Release模式下,编译器会对常量取值进行优化以提高程序效率,通常在编译前遇到常量,都会进行计算,得出一个新的常量值.

      #include <stdio.h>
      
      int main(int argc, char* argv[])
      {
      	int x = 1, y = 2,z = 3;
      	printf("常量+常量: %d\n", 10 + 25);
      	printf("变量+变量: %d\n", x + y);
      	printf("常量+变量: %d\n", 100 + x + y + z);
      	return 0;
      }
      

      观察Release模式下的汇编代码,下方代码不难看出,程序会将可以提前计算的常量值进行计算,并将该结果压栈,从而可以直接Push常量节约运算资源,另外常量折叠优化通常伴随有常量传播,如果两个变量在程序中从来都没有被修改过,也没有传入过参数,为了提升运行效率在VS2013编译器中会将这种变量自动的优化为常量.

      00B11000 | 56                       | push esi                              | main.c:4
      00B11001 | 8B35 9020B100            | mov esi,dword ptr ds:[<&printf>]      | 获取printf基地址,并存入esi
      00B11007 | 6A 23                    | push 0x23                             | 0x23 = 10 + 25 的结果
      00B11009 | 68 0021B100              | push consoleapplication1.B12100       | B12100:"常量+常量: %d\n"
      00B1100E | FFD6                     | call esi                              |
      00B11010 | 6A 03                    | push 0x3                              | 0x3 = x + y 的结果
      00B11012 | 68 1021B100              | push consoleapplication1.B12110       | B12110:"变量+变量: %d\n"
      00B11017 | FFD6                     | call esi                              |
      00B11019 | 6A 6A                    | push 0x6A                             | main.c:8
      00B1101B | 68 2021B100              | push consoleapplication1.B12120       | B12120:"常量+变量: %d\n"
      00B11020 | FFD6                     | call esi                              |
      00B11022 | 83C4 18                  | add esp,0x18                          |
      00B11025 | 33C0                     | xor eax,eax                           | main.c:9
      00B11027 | 5E                       | pop esi                               |
      00B11028 | C3                       | ret                                   | main.c:10
      

      窥孔优化: 一种很局部的优化方式,编译器仅仅在一个基本块或者多个基本块中,针对已经生成的代码,结合CPU自己指令的特点对一些认为可能带来性能提升的转换规则,或者通过整体的分析,通过指令转换,提升代码性能。

      这个窥孔,你可以认为是一个滑动窗口,编译器在实施窥孔优化时,就仅仅分析这个窗口内的指令。每次转换之后,可能还会暴露相邻窗口之间的某些优化机会,所以可以多次调用窥孔优化,尽可能提升性能

      基本的乘除法: 乘法与除法与加减法相同也有一组专用汇编指令,只不过乘除法的计算方式与加减法稍有不同,在Debug版与Release版中的表现也不同.

      #include <stdio.h>
      
      int main(int argc, char* argv[])
      {
      	int x = 10, y = 34,z = 22;
      	printf("x*y*z 结果是: %d\n", x*y*z);
      
      	int a = 1000, b = 20;
      	printf("a/b 结果是: %d\n", a / b);
      	return 0;
      }
      

      针对基本的乘除法的反汇编代码如下所示,第一个就是乘法的计算方式,第二个则是除法的计算方式.

      计算乘法是应遵循:
      如果乘数与被乘数都是8位,则把al做乘数,结果放在ax中.
      如果乘数与被乘数都是16位,将把ax做乘数,结果放在eax中.
      如果乘数与被乘数都是32位,将把eax做乘数,结果放在edx:eax中.

      004113DE | C745 F8 0A000000         | mov dword ptr ss:[ebp-0x8],0xA       | x = 0xA => 10
      004113E5 | C745 EC 22000000         | mov dword ptr ss:[ebp-0x14],0x22     | y => 0x14 => 34
      004113EC | C745 E0 16000000         | mov dword ptr ss:[ebp-0x20],0x16     | z => 0x20 => 22
      004113F3 | 8B45 F8                  | mov eax,dword ptr ss:[ebp-0x8]       | 参数移动
      004113F6 | 0FAF45 EC                | imul eax,dword ptr ss:[ebp-0x14]     | 执行 eax * y = eax
      004113FA | 0FAF45 E0                | imul eax,dword ptr ss:[ebp-0x20]     | 执行 eax * z = eax
      004113FE | 8BF4                     | mov esi,esp                          |
      00411400 | 50                       | push eax                             | push eax * y * z
      00411401 | 68 58584100              | push consoleapplication1.415858      | 415858:"x*y*z 结果是: %d\n"
      00411406 | FF15 14914100            | call dword ptr ds:[<&printf>]        | 输出乘法最终结果
      0041140C | 83C4 08                  | add esp,0x8                          |
      

      计算除法是应遵循:
      如果除数为8位则被除数为16位,则结果的商存放与al中,余数存放ah中.
      如果除数为16位则被除数为32位,则结果的商存放与ax中,余数存放dx中.
      如果除数为32位则被除数为64位,则结果的商存放与eax中,余数存放edx中.
      cdq指令扩展标志位 edx存储高位:eax存储低位

      00411416 | C745 D4 E8030000         | mov dword ptr ss:[ebp-0x2C],0x3E8    | a = 0x3E8 => 1000
      0041141D | C745 C8 14000000         | mov dword ptr ss:[ebp-0x38],0x14     | b = 0x14 => 20
      00411424 | 8B45 D4                  | mov eax,dword ptr ss:[ebp-0x2C]      | eax = ebp-0x2c => 0x3E8
      00411427 | 99                       | cdq                                  | 把eax的第31bit复制到edx的每个bit上
      00411428 | F77D C8                  | idiv dword ptr ss:[ebp-0x38]         | 除法 eax = [ebp-0x2C]/[ebp-0x38] => eax/0x14
      0041142B | 8BF4                     | mov esi,esp                          |
      0041142D | 50                       | push eax                             | 输出eax里面的值,就是除法结果.
      0041142E | 68 70584100              | push consoleapplication1.415870      | 415870:"a/b 结果是: %d\n"
      00411433 | FF15 14914100            | call dword ptr ds:[<&printf>]        |
      00411439 | 83C4 08                  | add esp,0x8                          |
      

      上方代码中所展示的都是基于Debug版本的编译方式,可以说该版本没有经过任何优化,所以乘除法是通过计算后得到的结果,下面这段代码是Release版本代码,你可以清楚地看出代码中并没有任何与计算乘除法有关的指令,这是因为编译器在编译的时候提前将结果计算出来并打成了常量值,这有助于提高程序的运算效率.

      002B1000 | 68 381D0000              | push 0x1D38                          | main.c:4
      002B1005 | 68 00212B00              | push consoleapplication1.2B2100      | 2B2100:"x*y*z 结果是: %d\n"
      002B100A | FF15 90202B00            | call dword ptr ds:[<&printf>]        |
      002B1010 | 6A 32                    | push 0x32                            | main.c:10
      002B1012 | 68 14212B00              | push consoleapplication1.2B2114      | 2B2114:"a/b 结果是: %d\n"
      002B1017 | FF15 90202B00            | call dword ptr ds:[<&printf>]        |
      002B101D | 83C4 10                  | add esp,0x10                         |
      002B1020 | 33C0                     | xor eax,eax                          | main.c:11
      002B1022 | C3                       | ret                                  | main.c:12
      

      递增/递减运算符: 递增递减运算符也是C语言中最常用的运算元素.

      #include <stdio.h>
      
      int main(int argc, char* argv[])
      {
      	int x = 10;
      	printf("x+1 = > %d\n", x + 1);
      	printf("x+=2 => %d\n", x -= 2);
      	printf("++x => %d\n", ++x);
      	printf("x++ => %d\n", x++);
      	return 0;
      }
      

      如下就是递增递减的代码片段,可以看出这几种的差别并不大,这里直接省略了.

      004113DE | C745 F8 0A000000         | mov dword ptr ss:[ebp-0x8],0xA       | 10
      004113E5 | 8B45 F8                  | mov eax,dword ptr ss:[ebp-0x8]       | eax = 10
      004113E8 | 83C0 01                  | add eax,0x1                          | eax = eax+1
      004113EB | 8BF4                     | mov esi,esp                          |
      004113ED | 50                       | push eax                             |
      004113EE | 68 58584100              | push consoleapplication1.415858      | 415858:"x+1 = > %d\n"
      004113F3 | FF15 14914100            | call dword ptr ds:[<&printf>]        |
      
      00411403 | 8B45 F8                  | mov eax,dword ptr ss:[ebp-0x8]       | eax = 10
      00411406 | 83E8 02                  | sub eax,0x2                          | eax = eax-2
      00411409 | 8945 F8                  | mov dword ptr ss:[ebp-0x8],eax       |
      0041140C | 8BF4                     | mov esi,esp                          |
      0041140E | 8B4D F8                  | mov ecx,dword ptr ss:[ebp-0x8]       |
      00411411 | 51                       | push ecx                             |
      00411412 | 68 68584100              | push consoleapplication1.415868      |
      00411417 | FF15 14914100            | call dword ptr ds:[<&printf>]        |
      

      复合运算符: 复合运算就是运算符中嵌套另一个运算表达式,该表达式就是符合运算表达式.

      #include <stdio.h>
      
      int main(int argc, char* argv[])
      {
      	int x = 10, y = 34,z = 22;
      
      	int a = (x + z + y);
      	int b = a * 3;
      	printf("当前b= %d\n", b);
      	return 0;
      }
      

      Debug反汇编代码如下,如果是Release那么这些变量也会被计算出结果并赋予一个常量,所以这里只能使用Debug版查看.

      004113DE | C745 F8 0A000000         | mov dword ptr ss:[ebp-0x8],0xA       | 10
      004113E5 | C745 EC 22000000         | mov dword ptr ss:[ebp-0x14],0x22     | 34
      004113EC | C745 E0 16000000         | mov dword ptr ss:[ebp-0x20],0x16     | 33
      004113F3 | 8B45 F8                  | mov eax,dword ptr ss:[ebp-0x8]       | eax = 10
      004113F6 | 0345 E0                  | add eax,dword ptr ss:[ebp-0x20]      | eax = eax + 33
      004113F9 | 0345 EC                  | add eax,dword ptr ss:[ebp-0x14]      | eax = eax + 34
      004113FC | 8945 D4                  | mov dword ptr ss:[ebp-0x2C],eax      | mov [ebp-0x2C], 10+33+34
      004113FF | 6B45 D4 03               | imul eax,dword ptr ss:[ebp-0x2C],0x3 | imul eax,77,03 => 77乘3结果存入eax
      00411403 | 8945 C8                  | mov dword ptr ss:[ebp-0x38],eax      | 赋值到临时变量
      00411406 | 8BF4                     | mov esi,esp                          | main.c:9, esi:__enc$textbss$end+109
      00411408 | 8B45 C8                  | mov eax,dword ptr ss:[ebp-0x38]      |
      0041140B | 50                       | push eax                             |
      0041140C | 68 58584100              | push consoleapplication1.415858      | 415858:"当前b= %d\n"
      00411411 | FF15 14914100            | call dword ptr ds:[<&printf>]        |
      00411417 | 83C4 08                  | add esp,0x8                          |
      

      多目运算符:

      int main(int argc, char* argv[])
      {
      	unsigned int temp;
      	scanf("%d",&temp);
      	printf("%d\r\n",temp == 0 ? 0:-1);    // 针对有符号数
      	printf("%d\r\n",temp == 0 ? 1:0);     // 针对无符号数
      	printf("%d\r\n",temp >= 1 ? 35:98);   // 大于等于
      	return 0;
      }
      

      针对有符号数

      0040F979  |.  8B4D FC       mov     ecx, dword ptr [ebp-4]
      0040F97C  |.  F7D9          neg     ecx
      0040F97E  |.  1BC9          sbb     ecx, ecx
      0040F980  |.  51            push    ecx                              ; /<%d>
      0040F981  |.  68 802E4200   push    00422E80                         ; |format = "%d"
      0040F986  |.  E8 45FFFFFF   call    printf                           ; \printf
      0040F98B  |.  83C4 08       add     esp, 8
      

      针对无符号数

      0040F990  |.  837D FC 00    cmp     dword ptr [ebp-4], 0
      0040F994  |.  0F94C2        sete    dl
      0040F997  |.  52            push    edx                              ; /<%d>
      0040F998  |.  68 802E4200   push    00422E80                         ; |format = "%d"
      0040F99D  |.  E8 2EFFFFFF   call    printf                           ; \printf
      0040F9A2  |.  83C4 08       add     esp, 8
      

      大于等于符号

      0040F9A5  |.  837D FC 01    cmp     dword ptr [ebp-4], 1
      0040F9A9  |.  1BC0          sbb     eax, eax
      0040F9AB  |.  83E0 3F       and     eax, 3F
      0040F9AE  |.  83C0 23       add     eax, 23
      0040F9B1  |.  50            push    eax                              ; /<%d>
      0040F9B2  |.  68 802E4200   push    00422E80                         ; |format = "%d"
      0040F9B7  |.  E8 14FFFFFF   call    printf                           ; \printf
      0040F9BC  |.  83C4 08       add     esp, 8
      
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://my.oschina.net/lyshark/blog/5550932,作者:LyShark,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:猜数字游戏 (C语言)

      下一篇:c++小项目《扫雷》

      相关文章

      2025-03-31 08:49:25

      C语言函数及分文件编程

      C语言函数及分文件编程

      2025-03-31 08:49:25
      C语言 , 变量名
      2025-03-26 09:31:37

      【数据结构】——拿捏 栈和队列

      【数据结构】——拿捏 栈和队列

      2025-03-26 09:31:37
      C语言 , 数据结构
      2024-11-06 07:24:46

      图的存储

      图的存储 

      2024-11-06 07:24:46
      存储 , 编程开发
      2024-11-06 07:12:42

      C语言从入门到精通——变量类型和常量类型

      C语言从入门到精通——变量类型和常量类型

      2024-11-06 07:12:42
      C语言 , 变量
      2024-11-01 09:13:56

      C语言入门:if,switch语句介绍

      if语句是一种条件控制语句,可以根据条件执行不同的代码。

      2024-11-01 09:13:56
      C语言 , switch , 代码
      2024-11-01 09:13:56

      C语言入门:循环语句的介绍

      C语言入门:循环语句的介绍

      2024-11-01 09:13:56
      C语言 , 循环 , 表达式
      2024-10-22 07:46:59

      基于SpringBoot+Vue的C语言在线评测系统的详细设计和实现(源码+lw+部署文档+讲解等)

      基于SpringBoot+Vue的C语言在线评测系统的详细设计和实现(源码+lw+部署文档+讲解等)

      2024-10-22 07:46:59
      C语言 , 代码
      2024-10-21 09:45:28

      C语言实现扫雷(标记/取消标记雷、自动展开)

      C语言实现扫雷(标记/取消标记雷、自动展开)

      2024-10-21 09:45:28
      C语言 , 标记 , 输入
      2024-10-21 09:45:28

      C语言实现简易三子棋

      C语言实现简易三子棋

      2024-10-21 09:45:28
      C语言 , 代码 , 数组
      2024-10-21 09:45:17

      基本图形的打印

      基本图形的打印

      2024-10-21 09:45:17
      C语言 , 打印 , 输出
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5239523

      查看更多

      最新文章

      C语言函数及分文件编程

      2025-03-31 08:49:25

      【数据结构】——拿捏 栈和队列

      2025-03-26 09:31:37

      图的存储

      2024-11-06 07:24:46

      C语言从入门到精通——变量类型和常量类型

      2024-11-06 07:12:42

      C语言入门:if,switch语句介绍

      2024-11-01 09:13:56

      C语言入门:循环语句的介绍

      2024-11-01 09:13:56

      查看更多

      热门文章

      Java学习之算术运算符两只老虎

      2023-04-19 09:23:13

      Lambda函数

      2023-02-08 10:33:56

      R语言方差分析(ANOVA)学生参加辅导课考试成绩差异

      2023-02-08 10:33:55

      r语言中对LASSO,Ridge岭回归和Elastic Net模型实现

      2023-02-10 10:10:49

      通过SAS网络分析对人口迁移进行可视化分析

      2023-02-08 10:33:55

      R语言多分类logistic逻辑回归模型在混合分布模拟个人风险损失值评估的应用

      2023-02-10 05:50:40

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      C语言实现 || 21点(纸牌小游戏)

      几种距离度量

      C#应用程序多窗口消息传递

      萌妹子Python入门指北(四)

      c# OpenCV -1 直接比对两张图片

      呵呵,JavaScript 真好玩(苦笑脸)

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号