(四)羽夏看C语言——循环与跳转
写在前面
由于此系列是本人一个字一个字码出来的,包括示例和实验截图。本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
if语句
生活中,经常会有选择或者情况需要自己判断,计算机也是如此。所有的判断语句还是后面将要介绍的循环其实都是由JCC指令组成的。我们先给出如下代码示例:
#include <iostream>
using namespace std;
int main()
{
int c = 0;
int re = 0;
cout << "请输入数字:" << endl;
cin >> c;
if (c==0)
{
re = -c;
}
else if (c==1)
{
re = c + c;
}
else if (c==2)
{
re = 4;
}
else if (c==3)
{
re = c * c;
}
else if (c==4)
{
re = c + c + 5;
}
else if (c==5)
{
re = c;
}
else
{
re = -1;
}
system("pause");
return 0;
}
然后查看一下它的反汇编:

是不是很简单粗暴,每次需要判断是不是,不是再跳转,虽然结构清晰,但生成了大量的汇编代码,影响效率,写起来也挺费劲。
switch语句
switch语句在多情况判断上是用的最多的,是if语句的升级版,绝大多数情况比单纯的if-else高效的多,下面我们用代码揭开它神秘的面纱:
#include <iostream>
using namespace std;
int main()
{
int c = 0;
int re = 0;
cout << "请输入数字:" << endl;
cin >> c;
switch (c)
{
case 0:
re = -c;
break;
case 1:
re = c + c;
break;
case 2:
re = 4;
break;
case 3:
re = c * c;
break;
case 4:
re = c + c + 5;
break;
case 5:
re = c;
break;
default:
re = -1;
break;
}
system("pause");
return 0;
}
然后我们查看它的反汇编:

让我们分析一下比较有意思的反汇编:
mov eax,dword ptr [ebp-0Ch]
mov dword ptr [ebp+FFFFFF20h],eax
cmp dword ptr [ebp+FFFFFF20h],5
ja 0047255F
mov ecx,dword ptr [ebp+FFFFFF20h]
jmp dword ptr [ecx*4+004725C8h]
ebp-0Ch就是c的地址,它先比较这个东西是否大于5,如果大于直接到转到0x0047255F这个地址,也就是default语句,看来编译器还是挺“聪明的”。然而最“聪明”的不在这里,而是jmp dword ptr [ecx*4+004725C8h]这句汇编。让我们看看0x04725C8这个地址到底存储的是什么东西:
首先打开内存窗口,输入那个地址,然后在内存窗口显示右键选中四个字节整数,没有文本,十六进制显示即可。得到如下图结果:

如果你细心的话,你会发现这里面存储的都是每个case的地址,被称为地址表。我只需计算出一次结果,就可以跳转到我需要的位置。
咱们举的例子是情况连续的时候,如果不连续但差距不算太大呢,我们尝试把case 3删掉,看看有什么情况出现。

- 反汇编 -

- 地址表 -
可以看出表的成员个数不变,但被删除的case的地址处被填充了default语句的地址。编译器可以通过某种推断来实现地址表的构建提高运行效率,但是如果每个case没有任何规律可言的话,那会怎么样呢?
#include <iostream>
using namespace std;
int main()
{
int c = 0;
int re = 0;
cout << "请输入数字:" << endl;
cin >> c;
switch (c)
{
case 0:
re = -c;
break;
case 15:
re = c + c;
break;
case 200:
re = 4;
break;
case 489:
re = c + c + 5;
break;
case 542:
re = c;
break;
default:
re = -1;
break;
}
system("pause");
return 0;
}
然后看一下反汇编:

哈哈,这回编译器“找不到头脑了”,只能老老实实的用if-else的样式生成汇编了。
循环语句
循环语句应该是编程中经常会用到的语句。所有的形式示例如下:
for语句
for (int i = 0; i < 5; i++)
{
//do something
}
while语句
int i;
do
{
//do something
} while (i<5);
do语句
int i;
while (i<5)
{
//do something
}
在汇编层面,所有循环到汇编的本质都是一样的,下面我们用代码进行验证:
#include <iostream>
int main()
{
int c = 0;
//for循环
for (int i = 0; i < 5; i++)
{
c++;
}
//do循环
int i = 0;
do
{
c++;
i++;
} while (i < 5);
//while循环
i = 0;
while (i < 5)
{
c++;
i++;
}
system("pause");
return 0;
}
然后编译运行,查看它的反汇编,结果如下:

- for循环 -

- do循环 -

- while循环 -
跳转语句
break、continue、goto被我统称为跳转语句。break和continue语句经常在循环语句和switch语句出现,经常和if配套以判断是否不符合循环条件跳出而使用。翻译到汇编层面,它不过就是一条jmp指令,switch语句的已经体现了。goto语句翻译到汇编也是一条jmp指令,但如果处理不善,就会打乱程序执行流程出现不太可预测的结果,不太建议使用。那我们做一个循环语句的,其他自行探索实验,代码如下:
#include <iostream>
using namespace std;
int main()
{
for (int i = 0; i < 10; i++)
{
label:
if (i==2)
continue;
if (i == 7)
goto label;
if (i==8)
break;
}
system("pause");
return 0;
}

for each语句
经查阅,这个语句仅在微软的编译器里面有。所以本人还是略微做一下实验,来看看for each语句到底为我们做了什么东西。在实验之前,需要通过项目属性页-C/C++-语言来关闭符合模式,代码如下:
#include <iostream>
using namespace std;
int main()
{
int nums[] = { 1,2,3,4,5,6 };
int num = 0;
for each (int var in nums)
{
num += var;
}
system("pause");
return 0;
}
然后看一下反汇编:

一个简简单单的for each却为我们生成了好几行代码,剩下的还请自行探索。
下一篇
(四)羽夏看C语言——循环与跳转的更多相关文章
- (三)羽夏看C语言——进制
写在前面 由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...
- (八)羽夏看C语言——C番外篇
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...
- (五)羽夏看C语言——结构体与类
写在前面 由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...
- (二)羽夏看C语言——容器
写在前面 由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...
- (一)羽夏看C语言——简述
"羽夏看C语言"介绍什么 本系列从汇编的角度,比较翔实的介绍C语言.C++和C其实是一样的东西,C++的编译器只是更强大,更能帮助我们写代码,例如模板.没有特殊说明,本系列不会 ...
- (六)羽夏看C语言——函数
写在前面 由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...
- (七)羽夏看C语言——模板(C++)
写在前面 由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...
- (九)羽夏看C语言——C++番外篇
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...
- 羽夏看Win系统内核——简述
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...
随机推荐
- SSRF漏洞入门篇
SSRF漏洞,又名服务端请求伪造漏洞. PHP中下列函数使用不当会导致SSRF: file_get_contents().fsockopen().curl_exec()函数(源码审计的时候注意点儿): ...
- 大数据学习(23)—— ZooKeeper实战
本片介绍两方面内容,一方面是命令行操作,另一方面是Java调用API. ZooKeeper集群环境的搭建在Hadoop集群搭建里已经讲过了,这里不再赘述,本篇内容基于zk3.5.8. 这里补充一点,除 ...
- Python小白的数学建模课-10.微分方程边值问题
小白往往听到微分方程就觉得害怕,其实数学建模中的微分方程模型不仅没那么复杂,而且很容易写出高水平的数模论文. 本文介绍微分方程模型边值问题的建模与求解,不涉及算法推导和编程,只探讨如何使用 Pytho ...
- JVM的内存管理机制-转载
JVM的内存管理机制 一.JVM的内存区域 对于C.C++程序员来说,在内存管理领域,他们既拥有每一个对象的"所有权",又担负着每一个对象生命开始到终结的维护责任. 对Java程序 ...
- JSP的执行原理、JSP的内置对象、四大作用域解析、MVC模式理解>从零开始学JAVA系列
目录 JSP的执行原理.JSP的内置对象.四大作用域解析.MVC模式理解 JSP的执行原理 这里拿一个小例子来解析JSP是如何被访问到的 首先将该项目部署到tomcat,并且通过tomcat启动 通过 ...
- Java 7 新特性之try-with-resources实践理解
想象这么一个情景,我们需要使用一个资源,在使用完之后需要关闭该资源,并且使用该资源的过程中有可能有异常抛出.此时我们都会想到用try-catch语句,在finally中关闭该资源.此时会有一个问题,如 ...
- Modify File Descriptor Limit on Linux
System-wide File Descriptor Limit Get current value: sysctl fs.file-max modify max fd limit: sysctl ...
- Java-Mybatis动态SQL整理
XML映射器 SQL映射文件的几个顶级元素: cache - 该命名空间的缓存配置 cache-ref - 引用其他命名空间的缓存配置 resultMap - 描述如何从数据库结果集中加载对象 sql ...
- Shell-13-常用文件目录
linux系统目录结构 环境变量文件 系统级 系统级变量文件对所有用户生效 #系统范围内的环境变量和启动文件. #不建议把要做的事情写在这里面,最好创建一个自定义的,放在/etc/profile.d ...
- 关于解决numpy使用sklearn时的警告问题
关于解决numpy使用sklearn时的警告问题 在使用的时候,出现提示 :219: RuntimeWarning: numpy.ufunc size changed, may indicate bi ...