电脑中KM是车里km代表什么意思思

&几乎每种程序设计语言的语法中都会有语句的循环,跳转。像最为熟知的C语言便有 for 、 while 、 do---while 等等。这些循环一般都很容易理解和使用,对于程序中逻辑的实现也很有帮助。
只是很多人不曾知道,这些循环、跳转在计算机内部、在底层是如何实现的,于是在出现问题时还是没有好的解决办法,或者是虽然写出来程序,对于内部的逻辑,却还是隔了一层迷雾。
比如有人对这样一个问题:
for( i=0 ; i& 10 ; i++)
printf(&%i&,i);
for语句里面的 i++ 是什么时候执行的呢? 当循环开始时,是先执行括号里的 i++ 还是printf(&%i&,i)? 也就是说 ,第一个打印的数字是0 还是 1?
我相信这个问题很多人都遇到过,就是当for 循环结束后 i 的值到底是多少不是很确定,在这个问题上犯难,是在不值得。如果你也曾有过这种疑问,那么这篇文章就很值得继续看下去。
这篇文章将拨开迷雾,让你看到循环的本质。
这篇文章主要谈一下C中的这些循环, 跳转语句的内部实现机制。通过深入了解他们的内在,将让你在编程的时候逻辑更加清晰,出现问题的时候也更容易排查。
注:这篇文章中会涉及到一些基本的汇编知识,我们将通过分析&for 、 while 、 do---while &等的汇编表示形式,来弄清楚他们的实现机理。
&if--else是基本的条件转移控制指令,也可以说是程序循环跳转实现的基础。
先看一个具体的例子,函数absdiff()比较两个参数x,y 的大小,返回他们差的绝对值。
我们创建了对于的C语言版本(a)、goto形式的版本(b)、 以及其对应的汇编形式(c):
创建goto版本是为了能更好的理解他的汇编形式。因为里面的goto语句很类似于汇编中的跳转语句。
(a)中 的C代码应该不用多做解释了吧,大家应该都能看懂。
(b)中的got0语句形式:第4 行是一个跳转语句,跳转到执行第8 行。也就是说当第3 行的条件满足的时候,跳转到第8 行执行。如果第3 行的条件不满足,则执行第 5 行的语句。 然后无条件跳转到代码的结尾:& goto done;& 使用goto 语句通常被认为是一种不好的 编程风格,因为这样的语句通常难于调试和阅读,这里使用goto语句是为了构造出一种类似汇编实现的C语句。
(c)就是我们要讨论的重点了。其实条件跳转指令的汇编形式和他的goto形式有一定的相似之处。有语句跳转的时候都是这样的过程:先判断是否满足某个条件,如果满足,则跳到一个指定的的代码段继续执行程序,如果不满足,则执行另一条语句。
为了弄清楚它内部是如何实现的,现在我们来详细看一下他的汇编指令形式(c)
程序的 1 、2 行取得x y 的值。放在寄存器 edx eax 中,第三行比较x y 的大小(也就是比较edx eak &的大小)如果x & y 则跳到 .L2的地方执行(8 、9 行)执行x - y ,并将结果放在返回值中,然后程序顺序执行到程序结束处 .L3,反之,如果第三行判断结果是x&y ,则语句不会跳转,顺序执行y-x,并跳转到程序结束处 .L3.
现在,我们基本了解if --else 的执行机理了。主要是先判断条件值,从这个例子出发就是第 3 条语句: cmpl &%eax,%edx。学过汇编的同学应该知道,cmpl是一条比较指令,他的执行会影响标志位。做个简单的假设: cmpl & & A,B 是比较A,B两个数的大小,比较结果存放在标志位 F 中,当A&B时,F为0,A&BF为1。 后面的jge &.L是跳转语句,他的执行是和上一步比价的结果相关的,这里也就反映在标志位F 当中。当F 为1时(A&B),则跳转到 .L2执行 B-A。当比较结果为A&B 查看后标志位为0,则jge不跳转, 程序继续往下执行。
C中的if --else 的通用模板是这样的:
这里的 test-expr 是一个整数表达式,它的值为真(1、&0)则会执行第一个分支语句 , 否则执行第二个。但不管怎么样,都只会执行其中的一个。
对于这种模板,汇编的实现通常会用下面的形式:(这里用C语言描述)
汇编器会为 then-statement 和else-statement产生各自的代码快 ,通过条件跳转来执行相应的代码。
注意:程序并不是智能的,执行跳转的时候只会有两种判断(真和假),而且内部的跳转形式都是基于 go to 模式。所以说虽然goto 在编程中要少用,但在理解程序跳转的时候还是很重要的。我想因为goto 的实现方式和程序最终的实现方式如此的相似,才在C中引入goto 吧。
do---while
C中提供了多中循环结构,do-while &while 和 for ,然而汇编中没有相应的指令存在。通过上面对 if -else 的分析, 已经知道了 C 中条件跳转在汇编中的基本实现方式(goto),现在要讨论的这些循环,在循环中都有一个条件判断的环节,当条件满足时,继续循环体, 如果条件不满足,则跳出循环体。和if-else 不同的在于这里的条件表达式可能会有改变,也就是每次判断的条件和上次不同。
只要理解了上面的if-else 的内容 ,其他的循环都能通过对if -else 的改进来实现。先给出这些循环的goto 形式,就能很快推测出其内部的实现方式。
通用形式:
do-while的通用形式如下:
  body-staement
  while(test-expr)
这个循环的效果就是反复执行 body-staement,对test-expr进行求值,如果求值结果不是0 则继续执行。可以看到,body-statement至少会被执行一次。
do-while 的通用形式可翻译为 如下所示的goto 语句:
  body-statement
  t=test-
对于上面的goto形式, 可以先想想汇编会是如何实现的:把loop里的代码放在一个单独的代码段里面(包含if 的判断跳转部分)程序顺序执行下来,第一次执行不用判断条件。执行玩body-statement后判断条件,如果满足,则继续这个循环。
好了,下面看一个具体的例子:
这是一个计算阶乘的函数实现,
&(a)是c代码, &
(c)是对应的汇编形式
(b)是汇编中寄存器和变量的映射关系
(a)中的代码比较简单就不在解释了。现在看(c)中的代码:
第 1 行是获得函数参数n的值,放在寄存器 edx 中,第 2 行设置 result =1 &第 3 行的 L2 表明这是一个循环体。 (c) 中的第 4、 5 行实现了 (a)中 5、 6 行的功能。
(c)中的第6 行判断循环的条件,如果条件满足,则执行第 7 行 的跳转语句。
和do- while的通用形式所描述的一样,body-staement至少会被执行一次,这从汇编代码中也有体现,观察循环体 L2,在L2 没有关于L2 的跳转代码,也就是说在程序顺序往下执行的情况下,L2 至少会被执行一次,然后在 L2 内部判断是否继续执行循环体 L2。
&whil循环和do-while类似,他的通用形式如下:
while(test-expr)
  body-statement
和do-while不同的是,他先对test-expr求值,所以body-statement可能一次都不被执行。将while翻译为机器码有多种方法,其中一种常见的方式i就是把他翻译成do-while的形式。在第一次执行循环体之前加一个判断条件,如果条件满足,则进入do-while的循环体,如果不满足,直接跳过循环体。也就是上面说的:body-statement可能一次都不被执行。
下面先把while转换为do-while循环:
if(!test-expr)
  body-statement
  while(test-expr);
接下来可以吧这个do-while循环转换为goto语句:
  body-statement
  t=test-
这个goto的版本和do-while的版本只是在循环体loop的前面加上了一个判断条件,如果条件满足, 就执行上面中的do-while循环体,如果不满足,直接跳过循环。
通过上面的goto版本,现在应该可以想一下while 的 汇编是如何实现了吧:
现在就可以猜测,while 的汇编只是在do-while汇编的基础上做出一些改动:在循环体loop之前加一个判断条件,如果条件成立,则执行loop,不成立则跳过loop。
下面还通过一个具体例子来说:
还是计算n 的阶乘,不过这次是用while实现
下面是C代码:
这很简单,就不做解释了,下面看他的goto形式:
和上面描述的一样,在3、4 行中加入了条件判断,如果条件不满足 第5行直接跳攻loop循环体,只有当条件满足时才进入循环体loop。再看loop中,7、8 行执行计算阶乘的必要操作,9、10行通过判断test-expr 决定是否继续循环。
好,下面来看while的汇编形式:
现在看汇编代码应该比较有经验了吧,这里的3、4 行执行条件判断,决定是否进入循环体.L10,相当于goto版本中的4、5 行,如果不满足,直接跳转到.L7的位置。
再看一下.L10 循环体:6、7 行执行阶乘的必要操作,相当于goto中的 7、8 行,这里的8、9 行判断循环是否继续,相当于goto中的9、10行。
for循环的通用形式如下;
for(init- test- update-expr)
  body-statement
大概在学C的时候会提到for 循环可以用while 来表示:
while(test-expr){
  body-statement
  update-expr
程序首先初始化表达式init-expr的值,然后进入循环,再循环中先对测试值test-expr求值,如果为假,则退出循环,否则执行循环体body-statement,并更新表达式update-expr的值。
基于前面讲过的do-while到while的转换,先给出do-whle形式:
然后将它转为goto代码:
和上面一样,我们将用一个实例来说明问题:
考虑用for 循环写的阶乘函数
用for循环写的计算阶乘的函数是从2 开始,这和前面的从1开始不同,不过这并不影响其逻辑实现的结构,这段代码中,for循环的组成如下:
通过上面的分析,可以得到其goto形式:
到现在为止 ,已经在实例中给出了他的C 形式和goto形式,现在请看他的汇编形式:
上面都解释了很多,这里就不在解释这个汇编指令了,通过上面应该都能看懂。
开始的问题
到现在,应该弄清楚文章开头所说的问题了吧
for( i=0 ; i& 10 ; i++)
printf(&%i&,i);
现在应该了解什么时候执行 i++ 设么时候执行printf(&%i&,i); 了吧。
按照我们的分析,执行顺序应该是这样的:
1、 初始化 i=0
2、判断条件是否满足 i&10 是否成立
3、如果成立则执行循环体printf(&%i&,i); 并执行自加运算 i++
可以这段代码在自己的编译器中运行一下,看首先打印出来的是0 &还是1 &(按照我们的分析,应该从0 开始答应哦)
&其实这篇文章阐述的道理很简单,就是C 语言中循环的实现问题。如果你在linux环境下操作的话,要理解这一部分就更容易了,在linux下可以直观的看到一个程序编译后的汇编形式,在自己电脑上分析自己的程序,这样学起来才更有兴趣,更深刻。
简单介绍:
linux下编译器:GCC、
可执行文件查看器:objdump、还有一个好像是 elfread,不确定了。
如果调试上面的for语句的话,可以用gdb调试器,这样能让程序一步步执行,并且跟踪变量的值。关于linux下的这些命令这里不是本文重点,不再介绍。
/yanlingyin/
一条鱼、yanlingyin@ 博客园&
阅读(...) 评论()工具类服务
编辑部专用服务
作者专用服务
如何实现信息的有效利用
21世纪是信息时代、网络时代,如何有效利用信息是我们主要关心的问题.文章主要从目前的信息环境和存在的问题出发,提出了提高信息资源利用率的有效途径.
作者单位:
邳州市炮车中心卫生院,江苏邳州,221327
年,卷(期):
机标分类号:
在线出版日期:
本文读者也读过
相关检索词
万方数据知识服务平台--国家科技支撑计划资助项目(编号:2006BAH03B01)(C)北京万方数据股份有限公司
万方数据电子出版社扫码登录是如何实现的? - 简书
扫码登录是如何实现的?
网页版微信刚推出时,无数人被它的登录方式惊艳了一下,不需要输入用户名密码,打开手机微信扫一扫,便自动登录。从原理上讲,二维码只能是一段文本的编码,如何用它实现快捷登录的呢?
打开网页版微信,可以看到如下的页面:
微信扫码界面
如果你用我查查、支付宝、新浪微博等软件扫码二维码,你会发现此二维码解析出来是如下的网址:
https://login./l/obsbQ-Dzag==
接下来详细介绍一下扫码登录具体的每个步骤:
扫码登录完整流程
①:用户 A 访问微信网页版,微信服务器为这个会话生成一个全局唯一的 ID,上面的 URL 中 obsbQ-Dzag== 就是这个 ID,此时系统并不知道访问者是谁。
②:用户A打开自己的手机微信并扫描这个二维码,并提示用户是否确认登录。
③:手机上的微信是登录状态,用户点击确认登录后,手机上的微信客户端将微信账号和这个扫描得到的 ID 一起提交到服务器
④:服务器将这个 ID 和用户 A 的微信号绑定在一起,并通知网页版微信,这个 ID 对应的微信号为用户 A,网页版微信加载用户 A 的微信信息,至此,扫码登录全部流程完成
扫码登录看起来神奇,主要是因为微信 APP 扫自家的码会做一些普通二维码软件不会做的额外的操作,那就是将当前已登录的微信和扫出来的 ID 提交到微信服务器,类似的应用还有扫码支付、扫码加公众号等功能,关于二维码在产品设计中的应用,推荐另一篇文章:《》。
我的公众号:PMCraft,每周推送产品相关原创文章,欢迎关注。
公众号 PMCraft

我要回帖

更多关于 车里km代表什么意思 的文章

 

随机推荐