7.4 C中的IO电子课件 计算机系统基础:C语言视角(RISC-V版).ppt
7.4 C中的IO电子课件 计算机系统基础:C语言视角(RISC-V版)C的I/O在C语言中,通过调用库函数实现输入/输出I/O库函数提供了比较复杂的功能实现机制:通过调用操作系统的服务例程完成输入缓冲输入缓冲示例示例#includeintmain()charinChar1;charinChar2;printf(Inputcharacter1:n);inChar1=getchar();printf(Inputcharacter2:n);inChar2=getchar();printf(Character1is%cn,inChar1);printf(Character2is%cn,inChar2);Inputcharacter1:A回车回车Inputcharacter2:Character1isACharacter2is程序没有等待第二个字符的输入,就像漏掉了第二个getchar函数的调用,为什么?getchar函数是从标准输入流中读一个字符,而不是直接从键盘读字符I/O流流一个一个抽象抽象:输入和输出发生在流上:输入和输出发生在流上基于基于字符字符的的I/O输入流输入流键盘键盘一个字符被键入,添到流的结尾处一个字符被键入,添到流的结尾处程序:从流的开头处,读取输入程序:从流的开头处,读取输入输出流输出流打印机打印机程序:将打印的字符,添到输出流的结尾处程序:将打印的字符,添到输出流的结尾处打印机,从输出流的开头处打印打印机,从输出流的开头处打印stdin/stdoutC语言语言标准输入流标准输入流stdin,缺省映射到键盘,缺省映射到键盘getchar,返回stdin中的下一个输入字符的ASCII码标准输出流标准输出流stdout,缺省映射到显示器,缺省映射到显示器putchar,把传递给它的ASCII码添加到stdout中C+,Java,相似的基于流的抽象,相似的基于流的抽象解释解释#includeintmain()charinChar1;charinChar2;printf(Inputcharacter1:n);inChar1=getchar();printf(Inputcharacter2:n);inChar2=getchar();printf(Character1is%cn,inChar1);printf(Character2is%cn,inChar2);Inputcharacter1:A回车回车Inputcharacter2:Character1isACharacter2isstdin:6510inChar1:AinChar2:nI/O流的实现流的实现通过在通过在I/O服务例程的基础上,增加了额外的服务例程的基础上,增加了额外的软件层实现的软件层实现的getchar()先从先从stdin中读字符,如果有字符,就不需要中读字符,如果有字符,就不需要进行系统调用进行系统调用使用使用I/O流,可以有效减少系统调用次数,从流,可以有效减少系统调用次数,从而而减少减少了由于系统状态切换带来的了由于系统状态切换带来的开销开销不必再从用户模式切换到机器模式,最后再从自陷不必再从用户模式切换到机器模式,最后再从自陷返回返回如果如果stdin中已经没有字符,则自陷进入操作中已经没有字符,则自陷进入操作系统系统getchar()的底层实现的底层实现01stdin:.byte 0,0,.#标准输入流,共标准输入流,共size个字节,初值均为个字节,初值均为0/null02inPt:.word.#指针,初值为指针,初值为stdin03num:.word0#stdin中的字符数,初值为中的字符数,初值为004.#省略代码省略代码01行:行:stdin标记的空间,即输入流的缓冲区,大小标记的空间,即输入流的缓冲区,大小以以1024个字节为例个字节为例02行:行:inPt标记的存储单元,存储的是输入流中下标记的存储单元,存储的是输入流中下一个字符的地址,即字符指针一个字符的地址,即字符指针03行:行:num标记的存储单元,存储的是输入流中还标记的存储单元,存储的是输入流中还有多少个剩余的字符有多少个剩余的字符05getchar:.#省略寄存器的保存代码省略寄存器的保存代码06lax5,inPt07lwx7,0(x5)#字符指针字符指针08lax6,num09lwx28,0(x6)#字符数字符数0Abeqzx28,trap#输入流中无字符,自陷输入流中无字符,自陷0Blbx8,0(x7)#读出读出stdin中的下一个字符,加载到中的下一个字符,加载到x8中中0Caddix7,x7,10Dswx7,0(x5)#指针指向下一个字符指针指向下一个字符0Eaddix28,x28,-10Fswx28,0(x6)#字符数递减字符数递减10jexit0609行:读出字符指针和字符数行:读出字符指针和字符数0A0F行:如果输入流中还有字符,就读出来,然行:如果输入流中还有字符,就读出来,然后将指针指向下一个字符,剩余的字符数递减后将指针指向下一个字符,剩余的字符数递减11trap:lax11,stdin#x11,字符串首地址,字符串首地址12addi x12,x0,1024#x12,输入流大小,输入流大小13addi x10,x0,8#gets,输入字符串服务例程,输入字符串服务例程14ecall#系统调用系统调用如果输入流中没有字符可以读取,调用操作系统的如果输入流中没有字符可以读取,调用操作系统的输入字符串服务例程输入字符串服务例程1114行行设置系统调用号(设置系统调用号(x10)为)为8将将x11设置为缓冲区首地址设置为缓冲区首地址stdin将缓冲区大小(将缓冲区大小(x12)设置为)设置为1024进行系统调用进行系统调用15lax5,stdin16lbx8,0(x5)#读出读出stdin中的第一个字符,加载到中的第一个字符,加载到x8中中17addix7,x5,1#指针指向下一个字符指针指向下一个字符18lax5,inPt19swx7,0(x5)1Aaddix10,x10,-1#字符数(在字符数(在gets的返回值的返回值x10中)递减中)递减1Blax6,num1Cswx10,0(x6)1Dexit:mvx10,x8#getchar的返回值的返回值x101E.#省略寄存器的恢复代码省略寄存器的恢复代码1Fret151C行:从系统调用返回后行:从系统调用返回后读出缓冲区中的第一个字符读出缓冲区中的第一个字符将指针指向下一个字符将指针指向下一个字符剩余的字符数递减剩余的字符数递减1D1F行:将读出的字符传到行:将读出的字符传到x10中,返回中,返回调用库函数调用库函数getchar如果输入流中还有字符可以读,编号为如果输入流中还有字符可以读,编号为2和和3的流程(用虚线表示)就不用执行的流程(用虚线表示)就不用执行putchar()将字符存入将字符存入stdout中中此时,还不会输出到显示器此时,还不会输出到显示器如果存入的是如果存入的是换行符换行符,或者,或者stdout已已满满,就,就自陷进入操作系统处理例程自陷进入操作系统处理例程由操作系统将由操作系统将stdout中的字符串输出中的字符串输出