注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

bash的循环语法及C的循环语法  

2012-10-28 22:18:16|  分类: Linux系统编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、循环
循环是一个语言中的基础设施,脚本语言中的bash和C语言中都有两种循环语句,一个是for,另一个是while语句。但是今天遇到了一个while的死循环,促使我想了一下for和while的区别,还特意在网上搜索了,大家也讨论了一下,有人也提取提到了两个循环中如果出现continue就会出现死循环,但是大家最后没有达成一致意见,这一点还是有点遗憾。
二、C语言中一个for循环的处理
[root@Harry illufor]# cat illufor.c
int foo()
{
    for (int i = 0 ; i < 10 ; i++ )
    {
        if (i < 0x12345)
        {
            continue;
        }   
        break;
    }
}
[root@Harry illufor]# objdump -dr illufor.o

illufor.o:     file format elf32-i386


Disassembly of section .text:

00000000 <_Z3foov>:
   0:    55                       push   %ebp
   1:    89 e5                    mov    %esp,%ebp
   3:    83 ec 10                 sub    $0x10,%esp 这些是一个函数的序言,或者说开场白惯例

   6:    c7 45 fc 00 00 00 00     movl   $0x0,-0x4(%ebp)  //int i = 0

   d:    eb 0d                    jmp    1c <_Z3foov+0x1c> 在对初始化变量赋值为零之后,无跳转跳转到接下来的

   f:    81 7d fc 44 23 01 00     cmpl   $0x12344,-0x4(%ebp)   if (i < 0x12345)
  16:    7f 11                    jg     29 <_Z3foov+0x29>  如果大于0x12344则跳出循环

  18:    83 45 fc 01              addl   $0x1,-0x4(%ebp)  这里是for循环中的将i变量递增操作

  1c:    83 7d fc 09              cmpl   $0x9,-0x4(%ebp) 这里对应for循环中的i < 10语句
  20:    0f 9e c0                 setle  %al
  23:    84 c0                    test   %al,%al
  25:    75 e8                    jne    f <_Z3foov+0xf> 如果小于等于9,前向跳转到之前的循环内

  27:    eb 01                    jmp    2a <_Z3foov+0x2a>

  29:    90                       nop
  2a:    c9                       leave 
  2b:    c3                       ret   
You have new mail in /var/spool/mail/root
[root@Harry illufor]#
这里说明了在for循环中,无论如何for语句中的最后一个语句都是会被执行的,但是对于while来说,没有人会处理这个情况。所以如果while中可能出现continue,尽量使用for循环
C99中对于continue的定义,看起来处理方式是很简单的,那就是在每个最小循环体的最后,所以for中的迭代条件是一定会被执行的。
A continue statement causes a jump to the loop-continuation portion of the smallest enclosing iteration statement; that is, to the end of the loop body. More precisely, in each of the statements
6.8.6.2 The continue statement
while (/* ... */) {
/* ... */
continue;
/* ... */
contin: ;
}

do {
/* ... */
continue;
/* ... */
contin: ;
} while (/* ... */);


for (/* ... */) {
/* ... */
continue;
/* ... */
contin: ;
}
三、bash中对于两种循环的处理
1、for循环处理
execute_for_command (for_command)
{
  identifier = for_command->name->word;

  list = releaser = expand_words_no_vars (for_command->map_list);对于for循环中的变量,这里进行一次性展开,然后在循环中对循环变量迭代绑定for中集合变量的内容
  for (retval = EXECUTION_SUCCESS; list; list = list->next)
{
……
      v = bind_variable (identifier, list->word->word, 0);  绑定for循环中变量的值,
……
      retval = execute_command (for_command->action); 执行for中的action,一次迭代。

}
}
2、execute_while_command
/* Values that can be returned by execute_command (). */
#define EXECUTION_FAILURE 1
#define EXECUTION_SUCCESS 0

  while (1)
    {
      return_value = execute_command (while_command->test);
……
   /* Need to handle `break' in the test when we would break out of the
         loop.  The job control code will set `breaking' to loop_level
         when a job in a loop is stopped with SIGTSTP.  If the stopped job
         is in the loop test, `breaking' will not be reset unless we do
         this, and the shell will cease to execute commands. */
      if (type == CMD_WHILE && return_value != EXECUTION_SUCCESS) 返回值错误时退出循环
    {
      if (breaking)
        breaking--;
      break;
    }
      if (type == CMD_UNTIL && return_value == EXECUTION_SUCCESS)
    {
      if (breaking)
        breaking--;
      break;
    }

……
      body_status = execute_command (while_command->action);
3、本质区别
在while循环中执行的是一个命令,然后判断一个命令的返回值,对于for循环来说,for语句中的变量集合只会被展开一次,对于while来说,条件中是一个命令,每次循环的时候都会执行一次条件中的命令。
这种实现对于unix的命令工具也有一个有意思的影响,那就是两个非常简单的true程序和false程序,它们简单到任何一个C程序员都可以编写,因为两个程序的功能就是一个始终返回成功(返回值为0),一个始终返回失败(返回值为1)。这本质上是一个适配的过程,因为while的条件中只接受一个命令的返回值,所以需要通过一个简单的true来实现一个无限循环。这和linux下的/dev/numm(windows下的NIL)都是相同的一个特殊适配设备,因为某些地方必须使用一个文件接受者,但事实上又没有人关心这个输出,所以定义这种文件来适配丢弃输出。
四、bash中对于命令输出的换行的处理
之前曾经说过,bash在对变量展开的时候会将其中的换行符替换为空白,这一点对于一些接收了命令输出的匹配处理可能会产生影响,也就是不能依赖换行符。做一个简单的例子大家就可以看到直观区别了。
[root@Harry illufor]# cat illufor.c
int foo()
{
    for (int i = 0 ; i < 10 ; i++ )
    {
        if (i < 0x12345)
        {
            continue;
        }   
        break;
    }
}
[root@Harry illufor]# echo `cat illufor.c` 可以看到,bash将cat的结果中的换行符全部替换为空格,相当于一个文件扁平化了。
int foo() { for (int i = 0 ; i < 10 ; i++ ) { if (i < 0x12345) { continue; } break; } }
[root@Harry illufor]#
  评论这张
 
阅读(810)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017