Unix下如何获取fread、fgetc等函数的特定错误(如EAGAIN)?
如何在读取管道后获取特定错误(如EAGAIN)?
使用read系统调用读取非阻塞管道时,能正确获取EAGAIN错误(通过errno),但改用标准IO的fgetc函数时,仅返回EOF,errno被置为0,只能通过ferror得知发生了错误,无法获取具体的错误类型。
以下是测试代码及运行输出:
测试代码
#include <assert.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> // 补充代码中缺失的buf定义 char buf[10]; int main() { int rw[2]; assert(!pipe(rw)); int r = rw[0], w = rw[1]; fcntl(r, F_SETFL, O_NONBLOCK); printf("This will return EAGAIN\n"); printf(" read -> %i\n", read(r, buf, 10)); printf(" errno = %i \"%s\" (EAGAIN=%i)\n", errno, strerror(errno), EAGAIN); errno = 0; FILE* f = fdopen(r, "r"); printf(" fgetc -> %i (EOF=%i) errno=%i\n", fgetc(f), EOF, errno); printf(" ferror -> %i\n", ferror(f)); }
运行输出
This will return EAGAIN read -> -1 errno = 11 "Resource temporarily unavailable" (EAGAIN=11) fgetc -> -1 (EOF=-1) errno=0 ferror -> 1
解决方案
1. 直接使用系统调用替代标准IO函数
标准IO库(stdio)的设计目标是提供带缓冲的便捷IO操作,它会封装底层系统调用,并且不会总是保留底层的错误码信息,尤其在非阻塞IO场景下,标准IO函数的行为并不适配。
直接使用read、write等系统调用可以直接获取底层错误码(如EAGAIN),这是处理非阻塞管道IO最可靠的方式。
2. 避免在标准IO中使用非阻塞文件描述符
POSIX标准并未定义标准IO函数与非阻塞文件描述符配合的行为,不同系统的实现可能存在差异。如果一定要使用标准IO,建议将文件描述符设置为阻塞模式,否则无法保证能正确获取到具体的错误类型。
如果必须使用非阻塞模式且要结合标准IO,部分系统允许通过fileno(f)获取流对应的文件描述符,然后在ferror(f)为真时检查errno(需在调用标准IO函数前重置errno为0),但这种方式不具备跨平台兼容性,且依赖具体的stdio实现。
内容的提问来源于stack exchange,提问作者vitiral
相关产品推荐
相关产品推荐

