文章标题】: 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
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!