好的,您实际上并不需要getc/putc,只需要一些执行缓冲 I/O 的函数和在某些情况下(例如退出程序)刷新 I/O 的操作。
(目前假设此缓冲不会用于控制台 I/O,即仅文件 I/O — 控制台 I/O 是交互式的,并且在使用 getc 时需要 putc 缓冲区刷新。进一步为简单起见,您只希望能够一次写入一个文件,一次读取一个文件,尽管混合 put/get ok。)
提供两个全局缓冲区,一个用于putc,一个用于getc。与每个缓冲区相关联的还有一个全局变量end,它可以是一个计数或指针,以及一个值max,它可以是编译时间常数或变量,它指示缓冲区大小。此外,putc 和getc 中的每一个都是文件描述符变量。 (对于max 的概念,Getc 需要一个真正的变量。)
putc 函数只接受一个参数,即要放置的字符;它应该将字符输入其缓冲区并增加相关联的end — 如果end 达到max,则使用带有参数 putc 文件描述符(全局)、putc 缓冲区(全局) 和 putc max (缓冲区大小)。您选择如何处理错误(使用消息退出程序(可能更简单),或者将错误返回给调用者?)。然后在返回调用者之前将end重置为开头,b/c缓冲区现在是空的。
getc 函数不接受任何参数并返回一个字符或 EOF 指示符,如果缓冲区不为空,则从缓冲区中获取字符以返回,并推进 end 位置。返回之前,如果达到max,则重置到开头。
但是,如果缓冲区为空(即end 位于开头),则使用系统调用#14 使用 getc 文件描述符、getc 缓冲区和 getc 缓冲区大小进行读取。如果该读取调用出错,则再次调用是否将错误打印到控制台并退出程序,或将错误代码返回给用户(前者可能更简单)。如果它返回 0,这意味着 EOF,所以将它(可能是 -1)返回给调用者而不是一个字符。
如果它得到一个非零字符数,则设置max该字符数,并将字符加载到end位置(如果您在这里,则在开头)以返回并增加end 的位置。如果end 的位置是max,则在返回之前将其重置为开头。
初始化:客户端消费者需要将文件描述符放入getc 和putc 的全局文件描述符中,以便它们与其他全局变量一起使用。
您还需要提供flush 类型的调用,main 或其他调用者应将其用作终止程序之前的最终操作。此刷新操作将使用系统调用 #15 来写入缓冲区中当前有许多字符(如果超过 0,并将指示器重置为空缓冲区)。
客户端还应该关闭 getc/putc 之外的文件,也许还应该清除文件描述符。 (您可以考虑提供执行这些操作的退出调用。)