处理错误码需考虑的因素
- 平台差异:不同操作系统(Unix类和Windows)对文件系统调用错误码的定义和数值不同。例如,在Linux中
open
函数出错返回-1
并设置errno
,而Windows的文件操作函数(如CreateFile
)通过GetLastError
获取错误码,其数值与Unix类系统毫无关联。
- 错误类型对应:虽然不同平台错误码数值不同,但有些错误概念类似。比如文件不存在,在Linux下
errno
可能是ENOENT
,在Windows下GetLastError
返回ERROR_FILE_NOT_FOUND
,需将这些类似错误概念对应起来。
- 函数返回值约定:Unix类系统很多文件系统调用失败返回
-1
并设置errno
,而Windows部分函数返回INVALID_HANDLE_VALUE
等特殊值,然后通过GetLastError
获取错误码,要注意这些不同约定。
通用错误处理框架设计
- 定义抽象错误类型:
typedef enum {
ERR_FILE_NOT_FOUND,
ERR_PERMISSION_DENIED,
ERR_DISK_FULL,
// 其他常见文件系统相关错误
ERR_UNKNOWN
} FileError;
- 平台特定错误映射函数:
- 针对Unix类系统,编写函数将
errno
映射到自定义错误类型:
FileError map_unix_errno(int errnum) {
switch (errnum) {
case ENOENT:
return ERR_FILE_NOT_FOUND;
case EACCES:
return ERR_PERMISSION_DENIED;
case ENOSPC:
return ERR_DISK_FULL;
default:
return ERR_UNKNOWN;
}
}
- 针对Windows系统,编写函数将`GetLastError`返回值映射到自定义错误类型:
FileError map_win_error(DWORD errnum) {
switch (errnum) {
case ERROR_FILE_NOT_FOUND:
return ERR_FILE_NOT_FOUND;
case ERROR_ACCESS_DENIED:
return ERR_PERMISSION_DENIED;
case ERROR_DISK_FULL:
return ERR_DISK_FULL;
default:
return ERR_UNKNOWN;
}
}
- 封装文件系统调用:
- 编写封装函数,在调用实际文件系统调用后,根据不同平台获取错误码并映射到自定义错误类型。例如,封装
open
函数:
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#define open _open
#else
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#endif
FileError my_open(const char *pathname, int flags, int mode, int *fd) {
*fd = open(pathname, flags, mode);
if (*fd == -1) {
#ifdef _WIN32
return map_win_error(GetLastError());
#else
return map_unix_errno(errno);
#endif
}
return ERR_UNKNOWN;
}
- 错误处理逻辑:
- 在调用封装函数后,根据返回的自定义错误类型进行统一的错误处理逻辑。例如:
int main() {
int fd;
FileError err = my_open("test.txt", O_RDONLY, 0, &fd);
if (err != ERR_UNKNOWN) {
switch (err) {
case ERR_FILE_NOT_FOUND:
printf("文件未找到\n");
break;
case ERR_PERMISSION_DENIED:
printf("权限不足\n");
break;
// 其他错误处理
default:
printf("未知错误\n");
break;
}
}
// 正常文件操作
if (fd != -1) {
close(fd);
}
return 0;
}