(四)羽夏看C语言——循环与跳转
2021-09-03 13:01
851 查看
写在前面
此系列是本人一个字一个字码出来的,包括示例和实验截图。本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正。 如有好的建议,欢迎反馈。码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作。如想转载,请把我的转载信息附在文章后面,并声明我的个人信息和本人博客地址即可,但必须事先通知我。
你如果是从中间插过来看的,请仔细阅读**(一)羽夏看C语言——简述** ,方便学习本教程。
if语句
生活中,经常会有选择或者情况需要自己判断,计算机也是如此。所有的判断语句还是后面将要介绍的循环其实都是由
JCC指令组成的。我们先给出如下代码示例:
#include <iostream> using namespace std; //如果是C,请自行将头文件包含改为 stdio.h 和 stdlib.h //将 cout 改为 printf_s(可以 printf,但微软编译器编译会报错,自行科普) 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; //如果是C,请自行将头文件包含改为 stdio.h 和 stdlib.h //将 cout 改为 printf_s(可以 printf,但微软编译器编译会报错,自行科普) //将 cin 改为 scanf_s(可以 scanf,但微软编译器编译会报错,自行科普) 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; //如果是C,请自行将头文件包含改为 stdio.h 和 stdlib.h //将 cout 改为 printf_s(可以 printf,但微软编译器编译会报错,自行科普) //将 cin 改为 scanf_s(可以 scanf,但微软编译器编译会报错,自行科普) 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> //如果是C,请自行将头文件包含改为 stdio.h 和 stdlib.h 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; //如果是C,请自行将头文件包含改为 stdio.h 和 stdlib.h //将 cout 改为 printf_s(可以 printf,但微软编译器编译会报错,自行科普) 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; //如果是C,请自行将头文件包含改为 stdio.h 和 stdlib.h //将 cout 改为 printf_s(可以 printf,但微软编译器编译会报错,自行科普) 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语言第八回合:分支、循环和跳转
- 3 C语言 流程控制 循环 跳转
- c语言 三大循环 四大跳转 和判断语句
- 详解C语言 三大循环 四大跳转 和判断语句
- C语言while循环语句 do while语句 for循环语句
- ARM嵌入式学习--OK6410裸板程序--2.GPIO控制LED跑马灯(从ARM汇编跳转到C语言)
- C语言循环的小艺术
- (C语言)循环与递归求斐波那契数
- 数据结构双向循环链表的C语言实现(插入,查询,删除)
- C语言中的循环结构
- 【C语言探索之旅】 第一部分第七课:循环语句
- 链式循环队列实现(C语言)
- 五、数据结构基础之循环队列C语言实现
- 32位汇编——c语言循环do——while
- 循环队列(创建队列,入队,出队)C语言实现
- C语言实现队(循环队列)
- C语言实现按位循环左移和循环右移
- 循环(for,while,do...while)、控制跳转语句、方法
- C语言——对于循环的初步认识