如何在C程序中可移植地检测缓冲流的待处理输入输出
可移植实现方案说明
纯C标准没有提供查询stdio缓冲流(stdin/stdout/stderr)剩余待处理数据的标准化API,不存在100%兼容所有C语言运行环境的实现,但可以通过平台判断的方式,实现兼容绝大多数主流系统的方案:
输出流待输出数据检测
- 仅需清除待输出数据的场景:直接调用标准库函数
fflush(FILE *stream)即可,该函数是C89以来的标准函数,完全可移植。 - 需要查询待输出数据量的场景:通过不同libc的非标准扩展实现,主流实现的查询逻辑如下:
- glibc(Linux等环境):
stream->_IO_write_ptr - stream->_IO_write_base - MSVCRT(Windows环境):
stream->_cnt - BSD libc(macOS、FreeBSD等环境):
stream->_p - stream->_bf._base
- glibc(Linux等环境):
输入流待输入数据检测
用户态stdio缓冲待读数据
和输出流逻辑一致,通过对应libc的扩展字段查询:
- glibc:
stream->_IO_read_end - stream->_IO_read_ptr - MSVCRT:
stream->_cnt - BSD libc:
stream->_r
内核态未读数据查询
如果需要检测还未进入进程stdio缓冲、停留在内核缓冲区的待输入数据,可通过以下平台原生API实现:
- POSIX兼容环境(Linux、macOS、BSD、Android等):使用
poll设置零超时非阻塞查询:
#include <poll.h> int has_pending_input(int fd) { struct pollfd pfd = {.fd = fd, .events = POLLIN}; return poll(&pfd, 1, 0) > 0; } // 检测stdin调用方式:has_pending_input(fileno(stdin))
- Windows环境:使用
PeekNamedPipe查询标准输入句柄:
#include <windows.h> int has_pending_stdin_input(void) { DWORD available_bytes = 0; PeekNamedPipe(GetStdHandle(STD_INPUT_HANDLE), NULL, 0, NULL, &available_bytes, NULL); return available_bytes > 0; }
编译时通过_WIN32、__linux__、__APPLE__等预定义宏判断运行平台,调用对应实现即可覆盖绝大多数使用场景。
内容的提问来源于stack exchange,提问作者chqrlie
相关产品推荐
相关产品推荐

