首页
社区
课程
招聘
[旧帖] [原创]getchar和putchar 0.00雪花
发表于: 2009-10-31 20:38 6009

[旧帖] [原创]getchar和putchar 0.00雪花

2009-10-31 20:38
6009
文章标题】: getchar和putchar
【文章作者】: spacenumen
【作者邮箱】: flyicegood@163.com
【作者QQ号】: 410274624
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
   Getchar是一个特殊的函数,是获取用户数据的函数。在用户输入字符再按回车时,数据就存在缓存区中。
    例1【程序】
    #include<stdio.h>
    main()
    {
            char ch;
            ch=getchar();
            while(ch!='#')
            {
                    printf("        %c",ch);
                    ch=getchar();
            }
    }
    汇编代码:
    00401000  /$  55            push    ebp
    00401001  |.  8BEC          mov     ebp, esp
    00401003  |.  83EC 0C       sub     esp, 0C                          ;  三个变量空间
    00401006  |.  A1 3C604000   mov     eax, dword ptr [40603C]          ;  长度len减一
    0040100B  |.  83E8 01       sub     eax, 1
    0040100E  |.  A3 3C604000   mov     dword ptr [40603C], eax
    00401013  |.  833D 3C604000>cmp     dword ptr [40603C], 0            ;  长度len是否小于零
    0040101A  |.  7C 21         jl      short 0040103D
    0040101C  |.  8B0D 38604000 mov     ecx, dword ptr [406038]          ;  pstr缓存中原来就有数据
    00401022  |.  0FBE11        movsx   edx, byte ptr [ecx]              ;  取出该字符
    00401025  |.  81E2 FF000000 and     edx, 0FF
    0040102B  |.  8955 F8       mov     dword ptr [ebp-8], edx           ;  把该字符给变量str
    0040102E  |.  A1 38604000   mov     eax, dword ptr [406038]          ;  sptr指针指向下一个字符
    00401033  |.  83C0 01       add     eax, 1
    00401036  |.  A3 38604000   mov     dword ptr [406038], eax
    0040103B  |.  EB 10         jmp     short 0040104D
    0040103D  |>  68 38604000   push    00406038                         ;  长度是负数就表示是第一次提取缓存,就要先写入缓存
    00401042  |.  E8 AE000000   call    004010F5                         ;  写入缓存
    00401047  |.  83C4 04       add     esp, 4
    0040104A  |.  8945 F8       mov     dword ptr [ebp-8], eax           ;  第一个字符赋给str
    0040104D  |>  8A4D F8       mov     cl, byte ptr [ebp-8]
    00401050  |.  884D FC       mov     byte ptr [ebp-4], cl             ;  str赋给ch
    00401053  |>  0FBE55 FC     /movsx   edx, byte ptr [ebp-4]
    00401057  |.  83FA 23       |cmp     edx, 23                         ;  判断ch字符是不是结束标识#
    0040105A  |.  74 64         |je      short 004010C0
    0040105C  |.  0FBE45 FC     |movsx   eax, byte ptr [ebp-4]           ;  ch不是结束标识就输出ch
    00401060  |.  50            |push    eax
    00401061  |.  68 30604000   |push    00406030                        ;  ASCII TAB,"%c"
    00401066  |.  E8 59000000   |call    004010C4
    0040106B  |.  83C4 08       |add     esp, 8
    0040106E  |.  8B0D 3C604000 |mov     ecx, dword ptr [40603C]         ;  长度减-
    00401074  |.  83E9 01       |sub     ecx, 1
    00401077  |.  890D 3C604000 |mov     dword ptr [40603C], ecx
    0040107D  |.  833D 3C604000>|cmp     dword ptr [40603C], 0           ;  长度判断长度是否为零
    00401084      7C 22         jl      short 004010A8
    00401086  |.  8B15 38604000 |mov     edx, dword ptr [406038]         ;  取指针pstr
    0040108C  |.  0FBE02        |movsx   eax, byte ptr [edx]             ;  取pstr指向的字符
    0040108F  |.  25 FF000000   |and     eax, 0FF
    00401094  |.  8945 F4       |mov     dword ptr [ebp-C], eax          ;  将pstr指向的字符给字符变量w
    00401097  |.  8B0D 38604000 |mov     ecx, dword ptr [406038]         ;  getchar.00406E01
    0040109D  |.  83C1 01       |add     ecx, 1
    004010A0  |.  890D 38604000 |mov     dword ptr [406038], ecx         ;  指针pstr指向下一个字符
    004010A6  |.  EB 10         |jmp     short 004010B8
    004010A8  |>  68 38604000   |push    00406038
    004010AD  |.  E8 43000000   |call    004010F5                        ;  长度为零再次写人缓存
    004010B2  |.  83C4 04       |add     esp, 4
    004010B5  |.  8945 F4       |mov     dword ptr [ebp-C], eax
    004010B8  |>  8A55 F4       |mov     dl, byte ptr [ebp-C]
    004010BB  |.  8855 FC       |mov     byte ptr [ebp-4], dl            ;  将w赋给ch字符
    004010BE  |.^ EB 93         \jmp     short 00401053
    004010C0  |>  8BE5          mov     esp, ebp                         ;  结束
    004010C2  |.  5D            pop     ebp
    004010C3  \.  C3            retn
      这个程序是简单的用getchar获取用户的输入,再输出。getchar一般是两个gechar函数配合循环使用的。从汇编代码中分析一下getchar的流程:
    getchar函数有两个全局的变量长度len,和指向缓存区的指针。getchar函数开头就检查缓存区的长度,判断缓存区是否有数据,缓存区没有数据
    就调用写入缓存的函数,等待用户输入数据,用户键入回车时,数据和回车键都存入了缓存区,缓存区有数据就直接用指针取当前指向的字符,取
    出一个数据指针就要指向下一个字符。将取出的字符赋给接收字符的变量ch,判断ch的值是否是结束符。不是结束符就输出字符ch。再判断缓存的
    长度,看看有没有数据,没有数据写入缓存。有数据提取当前指向的数据,再判断是否结束符。
  
      putchar和getchar的原理机制基本一致,这两个函数常常成对出现。再用一个例子分析getchar的实现机制。
  
  例2【程序】
  #include<stdio.h>
  
  main()
  {
          char ch;
          ch=getchar();
          while(ch!='#')
          {
                  putchar(ch);
                  ch=getchar();
          }
  }
  汇编代码:
  00401000  /$  55            push    ebp
  00401001  |.  8BEC          mov     ebp, esp                         ;  主函数
  00401003  |.  83EC 10       sub     esp, 10
  00401006  |.  A1 34604000   mov     eax, dword ptr [406034]          ;  长度减一getlen--
  0040100B  |.  83E8 01       sub     eax, 1
  0040100E  |.  A3 34604000   mov     dword ptr [406034], eax
  00401013  |.  833D 34604000>cmp     dword ptr [406034], 0            ;  和零比较小于零,没有数据,跳到输入缓存
  0040101A  |.  7C 21         jl      short 0040103D
  0040101C  |.  8B0D 30604000 mov     ecx, dword ptr [406030]          ;  缓存的指针pgetchar
  00401022  |.  0FBE11        movsx   edx, byte ptr [ecx]
  00401025  |.  81E2 FF000000 and     edx, 0FF
  0040102B  |.  8955 F8       mov     dword ptr [ebp-8], edx           ;  str取得缓存中pgetchar指向的字符
  0040102E  |.  A1 30604000   mov     eax, dword ptr [406030]          ;  指针pgetchar指向下一个字符
  00401033  |.  83C0 01       add     eax, 1
  00401036  |.  A3 30604000   mov     dword ptr [406030], eax
  0040103B  |.  EB 10         jmp     short 0040104D
  0040103D  |>  68 30604000   push    00406030                         ;  输入缓存
  00401042  |.  E8 D7010000   call    0040121E
  00401047  |.  83C4 04       add     esp, 4
  0040104A  |.  8945 F8       mov     dword ptr [ebp-8], eax           ;  str=输入的第一个字符
  0040104D  |>  8A4D F8       mov     cl, byte ptr [ebp-8]
  00401050  |.  884D FC       mov     byte ptr [ebp-4], cl             ;  把当前取出的字符str给字符变量ch
  00401053  |>  0FBE55 FC     /movsx   edx, byte ptr [ebp-4]           ;  取出字符变量ch
  00401057  |.  83FA 23       |cmp     edx, 23                         ;  比较ch是不是结束字符#
  0040105A  |.  0F84 A5000000 |je      00401105                        ;  是结束字符就跳出循环
  00401060  |.  A1 54604000   |mov     eax, dword ptr [406054]         ;  输出长度putlen减一
  00401065  |.  83E8 01       |sub     eax, 1
  00401068  |.  A3 54604000   |mov     dword ptr [406054], eax
  0040106D  |.  833D 54604000>|cmp     dword ptr [406054], 0           ;  输出长度和零比较小于零表示还没有输出,跳到输出
  00401074  |.  7C 28         |jl      short 0040109E
  00401076  |.  8B0D 50604000 |mov     ecx, dword ptr [406050]         ;  输出缓存区的指针pputchar
  0040107C  |.  8A55 FC       |mov     dl, byte ptr [ebp-4]            ;  字符变量ch
  0040107F  |.  8811          |mov     byte ptr [ecx], dl              ;  将ch变量的字符送到输出缓存区指针pputchar指向的空间
  00401081  |.  0FBE45 FC     |movsx   eax, byte ptr [ebp-4]           ;  ch
  00401085  |.  25 FF000000   |and     eax, 0FF                        ;  只取一个字符
  0040108A  |.  8945 F4       |mov     dword ptr [ebp-C], eax          ;  将刚输出的ch字符给变量temp
  0040108D  |.  8B0D 50604000 |mov     ecx, dword ptr [406050]         ;  输出缓存区的指针指向下一个地址空间
  00401093  |.  83C1 01       |add     ecx, 1
  00401096  |.  890D 50604000 |mov     dword ptr [406050], ecx
  0040109C  |.  EB 15         |jmp     short 004010B3
  0040109E  |>  68 50604000   |push    00406050                        ;  输出第一字符,创建输出缓存
  004010A3  |.  0FBE55 FC     |movsx   edx, byte ptr [ebp-4]
  004010A7  |.  52            |push    edx
  004010A8  |.  E8 5C000000   |call    00401109                        ;  创建输出缓存,并输出
  004010AD  |.  83C4 08       |add     esp, 8
  004010B0  |.  8945 F4       |mov     dword ptr [ebp-C], eax          ;  将刚输出的字符赋给字符变量temp
  004010B3  |>  A1 34604000   |mov     eax, dword ptr [406034]         ;  输入长度getlen减一
  004010B8  |.  83E8 01       |sub     eax, 1
  004010BB  |.  A3 34604000   |mov     dword ptr [406034], eax
  004010C0  |.  833D 34604000>|cmp     dword ptr [406034], 0           ;  再将长度getlen和0比较,如过小于零。表示输入全部取完,要重新写入缓存
  004010C7  |.  7C 21         |jl      short 004010EA
  004010C9  |.  8B0D 30604000 |mov     ecx, dword ptr [406030]         ;  没有取完,就取pgetchar指针指向的字符
  004010CF  |.  0FBE11        |movsx   edx, byte ptr [ecx]
  004010D2  |.  81E2 FF000000 |and     edx, 0FF
  004010D8  |.  8955 F0       |mov     dword ptr [ebp-10], edx         ;  取得的这个字符暂存在temp2里
  004010DB  |.  A1 30604000   |mov     eax, dword ptr [406030]         ;  指针变量pgetchar下一个字符
  004010E0  |.  83C0 01       |add     eax, 1
  004010E3  |.  A3 30604000   |mov     dword ptr [406030], eax
  004010E8  |.  EB 10         |jmp     short 004010FA
  004010EA  |>  68 30604000   |push    00406030
  004010EF  |.  E8 2A010000   |call    0040121E                        ;  重新写入getchar的缓存
  004010F4  |.  83C4 04       |add     esp, 4
  004010F7  |.  8945 F0       |mov     dword ptr [ebp-10], eax         ;  得到的第一个字符暂存在temp2里
  004010FA  |>  8A4D F0       |mov     cl, byte ptr [ebp-10]           ;  将temp2取得的输入字符赋给ch变量
  004010FD  |.  884D FC       |mov     byte ptr [ebp-4], cl
  00401100  |.^ E9 4EFFFFFF   \jmp     00401053
  00401105  |>  8BE5          mov     esp, ebp
  00401107  |.  5D            pop     ebp
  00401108  \.  C3            retn
  
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2009年10月31日 20:30:10

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (10)
雪    币: 234
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
能看懂c代码~~
但是汇编~~~
2009-11-1 09:49
0
雪    币: 31
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这不是讲一个东西嘛?
2009-11-4 19:58
0
雪    币: 83
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不错,很详细
2009-11-5 11:40
0
雪    币: 30
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
哎,不是很懂,要学习了
2009-11-5 12:48
0
雪    币: 137
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
c中两个简单的函数到汇编中就那么复杂
2009-11-5 13:12
0
雪    币: 12
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
函数能看懂,但汇编不知道
2009-11-9 23:39
0
雪    币: 156
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
汇编代码是LZ自己写的还是反编译出来的?
2009-11-10 09:51
0
雪    币: 442
活跃值: (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
学习了,有空在仔细看看
2009-11-10 18:40
0
雪    币: 16
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
这两个函数是系统的基本接口,在不同的系统甚至不同的库中都不一定相同的....
2009-11-10 21:32
0
雪    币: 324
活跃值: (26)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
11
是反编译出来
2009-11-12 20:11
0
游客
登录 | 注册 方可回帖
返回
//