1. 前言
The GNU C Library Reference Manual for version 2.35
2. 错误报告
Error Reporting
GNU C 库中的许多函数检测并报告错误情况,有时您的程序需要检查这些错误情况。例如,当您打开一个输入文件时,您应该验证该文件实际上是否正确打开,如果调用库函数失败,则打印一条错误消息或采取其他适当的措施。
本章描述错误报告工具的工作原理。您的程序应包含头文件 errno.h 以使用此功能。
2.1. 检查错误
Checking for Errors
大多数库函数返回一个特殊值来指示它们已失败。特殊值通常是 -1、空指针或为此目的而定义的常量(例如 EOF)。但是这个返回值只告诉你发生了错误。要找出它是什么类型的错误,您需要查看存储在变量 errno 中的错误代码。该变量在头文件 errno.h 中声明。
变量:volatile int errno
变量 errno 包含系统错误号。您可以更改 errno 的值。
由于 errno 被声明为 volatile,它可能会被信号处理程序异步更改;请参阅定义信号处理程序。但是,正确编写的信号处理程序会保存和恢复 errno 的值,因此您通常不需要担心这种可能性,除非在编写信号处理程序时。
程序启动时 errno 的初始值为零。在许多情况下,当库函数遇到错误时,它会将 errno 设置为非零值,以指示发生了什么特定的错误情况。每个函数的文档都列出了该函数可能出现的错误情况。并非所有库函数都使用这种机制;一些直接用返回错误代码来代替。
警告:许多库函数可能会将 errno 设置为一些无意义的非零值,即使它们没有遇到任何错误,即使它们直接返回错误代码。因此,通过检查 errno 的值来判断是否发生错误通常是不正确的。每个函数检查错误的正确方法在文档中都有记录。
可移植性说明:ISO C 将 errno 指定为“可修改的左值”而不是变量,从而允许将其实现为宏。例如,它的扩展可能涉及函数调用,如 *__errno_location ()。事实上,这就是 GNU/Linux 和 GNU/Hurd 系统上的情况。每个系统上的 GNU C 库都会为特定系统做任何适合的事情。
有一些库函数,如 sqrt 和 atan,在发生错误时返回完全合法的值,但也会设置 errno。对于这些函数,如果要检查是否发生错误,推荐的方法是在调用函数之前将 errno 设置为零,然后再检查其值。
所有错误代码都有符号名称;它们是 errno.h 中定义的宏。名称以“E”和大写字母或数字开头;您应该将这种形式的名称视为保留名称。请参阅保留名称。
错误代码值都是正整数并且都是不同的,但有一个例外:EWOULDBLOCK 和 EAGAIN 相同。由于这些值是不同的,因此您可以将它们用作 switch 语句中的标签;只是不要同时使用 EWOULDBLOCK 和 EAGAIN。您的程序不应对这些符号常量的特定值做出任何其他假设。
errno 的值不一定必须与这些宏中的任何一个相对应,因为某些库函数可能会在其他情况下返回它们自己的其他错误代码。唯一保证对特定库函数有意义的值是本手册为该函数列出的值。
除了在 GNU/Hurd 系统上,几乎任何系统调用都可以返回 EFAULT,如果它被赋予一个无效的指针作为参数。由于这只会由于程序中的错误而发生,并且由于它不会发生在 GNU/Hurd 系统上,因此我们通过在各个函数的描述中不提及 EFAULT 来节省空间。
在一些 Unix 系统中,许多系统调用也可以返回 EFAULT,如果作为参数给出一个指向栈的指针,并且内核由于某种模糊的原因尝试扩展栈失败。如果发生这种情况,您可能应该尝试在该系统上使用静态或动态分配的内存而不是栈内存。
2.2. 错误代码
Error Codes
错误代码宏在头文件 errno.h 中定义。所有这些都扩展为整数常量值。其中一些错误代码不会出现在 GNU 系统上,但它们可以在其他系统上使用 GNU C 库出现。
-
宏:int EPERM
“Operation not permitted. 不允许操作” 只有文件(或其他资源)的所有者或具有特殊权限的进程才能执行该操作。
-
宏:int ENOENT
“No such file or directory. 没有相应的文件和目录” 对于在预期已经存在的上下文中引用的普通文件,这是一个“文件不存在”错误。
-
宏:int ESRCH
“No such process. 没有进程” 没有进程与指定的进程 ID 匹配。
-
宏:int EINTR
“Interrupted system call. 系统调用中断” 出现异步信号并阻止调用完成。发生这种情况时,您应该再次尝试调用。
您可以选择在处理完信号后恢复功能,而不是使用 EINTR 失败;参见被信号中断的原语。
-
宏:int EIO
“Input/output error. 输入/输出错误” 通常用于物理读取或写入错误。
-
宏:int ENXIO
“No such device or address. 没有这样的设备或地址” 系统尝试使用您指定的文件所代表的设备,但找不到该设备。这可能意味着设备文件安装不正确,或者物理设备丢失或未正确连接到计算机。
-
宏:int E2BIG
“Argument list too long. 参数列表太长” 当传递给正在使用 exec 函数之一执行的新程序的参数(请参阅执行文件)占用过多内存空间时使用。这种情况在 GNU/Hurd 系统上永远不会出现。
-
宏:int ENOEXEC
“Exec format error. 执行格式错误” 无效的可执行文件格式。这种情况由 exec 函数检测到;请参阅执行文件。
-
宏:int EBADF
“Bad file descriptor. 错误的文件描述符” 例如,已关闭的描述符上的 I/O 或读取仅为写入而打开的描述符(反之亦然)。
-
宏:int ECHILD
“No child processes. 没有子进程” 当没有任何进程可以操作时,此错误发生在应该操作子进程的操作上。
-
宏:int EDEADLK
“esource deadlock avoided. 避免了资源死锁” 分配系统资源会导致死锁情况。系统不保证会注意到所有此类情况。这个错误意味着你很幸运并且系统注意到了;它可能只是挂起。有关示例,请参见文件锁。
-
宏:int ENOMEM
“Cannot allocate memory. 无法分配内存” 系统无法分配更多的虚拟内存,因为它的容量已满。
-
宏:int EACCES
“Permission denied. 没有权限” 文件权限不允许尝试的操作。
-
宏:int EFAULT
“Bad address. 地址错误” 检测到无效指针。在 GNU/Hurd 系统上,这个错误永远不会发生;你会得到一个信号。
-
宏:int ENOTBLK
“Block device required. 需要阻止设备” 在需要的情况下给出了一个不是块特殊文件的文件。例如,尝试在 Unix 中将普通文件挂载为文件系统会出现此错误。
-
宏:int EBUSY
“Device or resource busy. 设备或资源繁忙” 无法共享的系统资源已在使用中。例如,如果您尝试删除当前挂载的文件系统的根文件,则会收到此错误。
-
宏:int EEXIST
“File exists. 文件已存在” 现有文件是在仅指定新文件才有意义的上下文中指定的。
-
宏:int EXDEV
“Invalid cross-device link. 无效的跨设备链接” 检测到试图在文件系统之间建立不正确的链接。这不仅在您使用链接时发生(请参阅硬链接),而且在您使用 rename 重命名文件时也会发生(请参阅重命名文件)。
-
宏:int ENODEV
“No such device. 无此设备” 将错误类型的设备提供给需要特定类型设备的函数。
-
宏:int ENOTDIR
“Not a directory. 不是目录” 需要目录时指定了不是目录的文件。
-
宏:int EISDIR
“Is a directory. 是目录” 您不能打开目录进行写入,也不能创建或删除指向它的硬链接。
-
宏:int EINVAL
“Invalid argument. 无效的参数” 这用于指示将错误参数传递给库函数时出现的各种问题。
-
宏:int EMFILE
“Too many open files. 打开的文件太多” 当前进程打开的文件太多,无法再打开。重复的描述符确实计入此限制。
在 BSD 和 GNU 中,打开文件的数量由通常可以增加的资源限制控制。如果您收到此错误,您可能需要增加 RLIMIT_NOFILE 限制或使其无限制;请参阅限制资源使用。
-
宏:int ENFILE
“Too many open files in system. 系统中打开的文件太多” 整个系统中有太多不同的文件打开。请注意,任何数量的链接通道都算作一个文件打开;请参阅链接通道。这个错误永远不会在 GNU/Hurd 系统上发生。
-
宏:int ENOTTY
“Inappropriate ioctl for device. 设备的 ioctl 不合适” 不适当的 I/O 控制操作,例如尝试在普通文件上设置终端模式。
-
宏:int ETXTBSY
“Text file busy. 文本文件忙” 尝试执行当前为写入而打开的文件,或写入当前正在执行的文件。通常,使用调试器运行程序会被认为是打开以进行编写,这会导致此错误。(这个名字代表“文本文件繁忙”。)这在 GNU/Hurd 系统上不是错误;必要时复制文本。
-
宏:int EFBIG
“File too large. 文件过大” 文件的大小将大于系统允许的大小。
-
宏:int ENOSPC
“No space left on device. 设备上没有剩余空间” 由于磁盘已满,对文件的写入操作失败。
-
宏:int ESPIPE
“Illegal seek. 非法搜索” 无效的查找操作(例如在管道上)。
-
宏:int EROFS
“Read-only file system. 只读文件系统” 试图修改只读文件系统上的某些内容。
-
宏:int EMLINK
“Too many links. 链接太多” 单个文件的链接数会变得太大。如果被重命名的文件已经拥有尽可能多的链接,则重命名可能会导致此错误(请参阅重命名文件)。
-
宏:int EPIPE
“Broken pipe. 管道坏了” 没有从管道的另一端读取进程。每个返回此错误代码的库函数也会生成一个 SIGPIPE 信号;如果未处理或阻塞,此信号将终止程序。因此,除非您的程序处理或阻止了 SIGPIPE,否则您的程序将永远不会真正看到 EPIPE。
-
宏:int EDOM
“Numerical argument out of domain. 域外的数值参数” 当参数值不属于定义函数的域时,由数学函数使用。
-
宏:int ERANGE
“Numerical result out of range. 数值结果超出范围” 当结果值由于上溢或下溢而无法表示时,由数学函数使用。
-
宏:int EAGAIN
“Resource temporarily unavailable. 资源暂时不可用” 如果您稍后再试,该调用可能会起作用。宏 EWOULDBLOCK 是 EAGAIN 的另一个名称;它们在 GNU C 库中总是相同的。
此错误可能在几种不同的情况下发生:
-
在选择了非阻塞模式的对象上尝试了会阻塞的操作。再次尝试相同的操作将阻塞,直到某些外部条件可以读取、写入或连接(无论操作如何)。您可以使用 select 找出何时可以进行操作;请参阅等待输入或输出。
可移植性说明:在许多较旧的 Unix 系统中,这种情况由 EWOULDBLOCK 指示,这是一个与 EAGAIN 不同的明显错误代码。为了使您的程序可移植,您应该检查这两个代码并将它们视为相同。
-
暂时的资源短缺使操作无法进行。fork 可以返回此错误。它表示预计短缺会过去,因此您的程序可以稍后再次尝试调用,它可能会成功。在重试之前延迟几秒钟可能是个好主意,以便其他进程有时间释放稀缺资源。这种不足通常相当严重并影响整个系统,因此通常交互式程序应该向用户报告错误并返回其命令循环。
-
-
宏:int EWOULDBLOCK
“Operation would block. 操作会阻塞” 在 GNU C 库中,这是 EAGAIN(上图)的另一个名称。在每个操作系统上,这些值始终相同。
许多旧 Unix 系统中的 C 库将 EWOULDBLOCK 作为单独的错误代码。
-
宏:int EINPROGRESS
“Operation now in progress. 操作正在进行中” 在选择了非阻塞模式的对象上启动了无法立即完成的操作。某些必须始终阻塞的函数(例如连接;请参阅建立连接)永远不会返回 EAGAIN。相反,它们返回 EINPROGRESS 以指示操作已经开始并且需要一些时间。在调用完成之前尝试操作对象返回 EALREADY。您可以使用 select 函数找出挂起的操作何时完成;请参阅等待输入或输出。
-
宏:int EALREADY
“Operation already in progress. 操作已经在进行中” 已在选择了非阻塞模式的对象上进行操作。
-
宏:int ENOTSOCK
“Socket operation on non-socket. 非套接字上的套接字操作” 当需要套接字时,指定了一个不是套接字的文件。
-
宏:int EMSGSIZE
“Message too long. 消息太长了” 在套接字上发送的消息的大小大于支持的最大大小。
-
宏:int EPROTOTYPE
“Protocol wrong type for socket. 套接字的协议类型错误” 套接字类型不支持请求的通信协议。
-
宏:int ENOPROTOOPT
“Protocol not available. 协议不可用” 您指定的套接字选项对套接字使用的特定协议没有意义。请参阅套接字选项。
-
宏:int EPROTONOSUPPORT
“Protocol not supported. 不支持协议” 套接字域不支持请求的通信协议(可能是因为请求的协议完全无效)。请参阅创建套接字。
-
宏:int ESOCKTNOSUPPORT
“Socket type not supported. 不支持套接字类型” 不支持套接字类型。
-
宏:int EOPNOTSUPP
“Operation not supported. 不支持操作” 不支持您请求的操作。一些套接字函数对所有类型的套接字都没有意义,而另一些函数可能不适用于所有通信协议。在 GNU/Hurd 系统上,当对象不支持特定操作时,许多调用都会发生此错误;这是一个通用的指示,表明服务器对该调用一无所知。
-
宏:int EPFNOSUPPORT
“Protocol family not supported. 不支持协议族” 不支持您请求的套接字通信协议系列。
-
宏:int EAFNOSUPPORT
“Address family not supported by protocol. 协议不支持地址族” 不支持为套接字指定的地址族;它与套接字上使用的协议不一致。请参阅套接字。
-
宏:int EADDRINUSE
“Address already in use. 地址已被使用” 请求的套接字地址已在使用中。请参阅套接字地址。
-
宏:int EADDRNOTAVAIL
“Cannot assign requested address. 无法分配请求的地址” 请求的套接字地址不可用;例如,您尝试为套接字指定一个与本地主机名不匹配的名称。请参阅套接字地址。
-
宏:int ENETDOWN
“Network is down. 网络坏了” 套接字操作失败,因为网络已关闭。
-
宏:int ENETUNREACH
“Network is unreachable. 网络不可达” 套接字操作失败,因为包含远程主机的子网不可访问。
-
宏:int ENETRESET
“Network dropped connection on reset. 重置时网络断开连接” 由于远程主机崩溃,网络连接被重置。
-
宏:int ECONNABORTED
“Software caused connection abort. 软件导致连接中止” 网络连接在本地中止。
-
宏:int ECONNRESET
“Connection reset by peer. 对等方重置连接” 网络连接因本地主机无法控制的原因而关闭,例如远程计算机重新启动或不可恢复的协议违规。
-
宏:int ENOBUFS
“No buffer space available. 没有可用的缓冲空间” 内核用于 I/O 操作的缓冲区都在使用中。在 GNU 中,这个错误总是 ENOMEM 的同义词。您可能会从网络运营中获得其中之一。
-
宏:int EISCONN
“Transport endpoint is already connected. 传输端点已连接” 您尝试连接已连接的套接字。请参阅建立连接。
-
宏:int ENOTCONN
“Transport endpoint is not connected. 传输端点未连接” 插座没有连接任何东西。当您尝试通过套接字传输数据时,您会收到此错误,而无需先指定数据的目的地。对于无连接套接字(对于数据报协议,例如 UDP),您将获得 EDESTADDRREQ。
-
宏:int EDESTADDRREQ
“Destination address required. 需要目的地地址” 没有为套接字设置默认目标地址。当您尝试通过无连接套接字传输数据时,您会收到此错误,而没有首先使用 connect 指定数据的目标。
-
宏:int ESHUTDOWN
“Cannot send after transport endpoint shutdown. 传输端点关闭后无法发送” 套接字已经关闭。
-
宏:int ETOOMANYREFS
“Too many references: cannot splice. 引用过多:无法拼接”
-
宏:int ETIMEDOUT
“Connection timed out. 连接超时” 具有指定超时的套接字操作在超时期间未收到响应。
-
宏:int ECONNREFUSED
“Connection refused. 连接被拒绝” 远程主机拒绝允许网络连接(通常是因为它没有运行请求的服务)。
-
宏:int ELOOP
“Too many levels of symbolic links. 太多级别的符号链接” 在查找文件名时遇到了太多级别的符号链接。这通常表示符号链接的循环。
-
宏:int ENAMETOOLONG
“File name too long. 文件名太长” 文件名太长(超过 PATH_MAX;请参阅文件系统容量限制)或主机名太长(在 gethostname 或 sethostname 中;请参阅主机标识)。
-
宏:int EHOSTDOWN
“Host is down. 宿主宕机了” 请求的网络连接的远程主机已关闭。
-
宏:int EHOSTUNREACH
“No route to host. 没有到主机的路由” 请求的网络连接的远程主机不可访问。
-
宏:int ENOTEMPTY
“Directory not empty. 目录不为空” 目录不为空,需要一个空目录。通常,当您尝试删除目录时会发生此错误。
-
宏:int EPROCLIM
“Too many processes. 进程太多” 这意味着尝试 fork 将超过每个用户对新进程的限制。有关 RLIMIT_NPROC 限制的详细信息,请参阅限制资源使用。
-
宏:int EUSERS
“Too many users. 用户太多” 文件配额系统因为用户太多而混乱。
-
宏:int EDQUOT
“Disk quota exceeded. 磁盘配额超标” 超出了用户的磁盘配额。
-
宏:int ESTALE
“Stale file handle. 过时的文件句柄” 这表明文件系统存在内部混乱,这是由于 NFS 文件系统的服务器主机上的文件系统重新排列或其他文件系统损坏所致。修复这种情况通常需要卸载,可能需要修复和重新安装文件系统。
-
宏:int EREMOTE
“Object is remote. 对象是远程的” 尝试使用已指定 NFS 挂载文件的文件名对远程文件系统进行 NFS 挂载。(这在某些操作系统上是一个错误,但我们希望它能够在 GNU/Hurd 系统上正常工作,因此不可能出现此错误代码。)
-
宏:int EBADRPC
“RPC struct is bad. RPC 结构不好”
-
宏:int ERPCMISMATCH
“RPC version wrong. RPC 版本错误”
-
宏:int EPROGUNAVAIL
“RPC program not available. RPC 程序不可用”
-
宏:int EPROGMISATCH
“RPC program version wrong. RPC 程序版本错误”
-
宏:int EPROCUNAVAIL
“RPC bad procedure for program. 程序的 RPC 错误过程”
-
宏:int ENOLCK
“No locks available. 没有可用的锁” 这由文件锁定设施使用;请参阅文件锁。GNU/Hurd 系统永远不会生成此错误,但它可能是对运行另一个操作系统的 NFS 服务器的操作导致的。
-
宏:int EFTYPE
“Inappropriate file type or format. 不适当的文件类型或格式” 该文件的操作类型错误,或者数据文件的格式错误。
在某些系统上,如果您尝试在非目录文件上设置粘滞位,则 chmod 会返回此错误;请参阅分配文件权限。
-
宏:int EAUTH
“Authentication error. 授权错误”
-
宏:int ENEEDAUTH
“Need authenticator. 需要验证器”
-
宏:int ENOSYS
“Function not implemented. 功能未实现” 这表明调用的函数根本没有实现,无论是在 C 库本身还是在操作系统中。当您收到此错误时,您可以确定此特定功能将始终因 ENOSYS 而失败,除非您安装新版本的 C 库或操作系统。
-
宏:int ENOTSUP
“Not supported. 不支持” 当某些参数值有效但它们请求的功能不可用时,函数会返回此错误。这可能意味着该函数根本没有实现特定的命令或选项值或标志位。对于对参数中给定的某些对象(例如文件描述符或端口)进行操作的函数,这可能意味着只有该特定对象(文件描述符、端口等)无法支持给定的其他参数;不同的文件描述符可能支持不同范围的参数值。
如果整个函数在实现中根本不可用,则返回 ENOSYS。
-
宏:int EILSEQ
“Invalid or incomplete multibyte or wide character. 无效或不完整的多字节或宽字符” 在解码多字节字符时,函数出现无效或不完整的字节序列,或者给定的宽字符无效。
-
宏:int EBACKGROUND
“Inappropriate operation for background process. 后台进程操作不当” 在 GNU/Hurd 系统上,当调用者不在终端的前台进程组中时,支持术语协议的服务器会为某些操作返回此错误。用户通常不会看到此错误,因为读取和写入等功能会将其转换为 SIGTTIN 或 SIGTTOU 信号。有关进程组和这些信号的信息,请参阅任务控制。
-
宏:int EDIED
“Translator died. 翻译死了” 在 GNU/Hurd 系统上,当文件被程序翻译并且翻译程序在启动时死机时,在它连接到文件之前打开文件会返回此错误。
-
宏:int ED
“?.” 有经验的用户会知道哪里出了问题。
-
宏:int EGREGIOUS
“You really blew it this time. 这次你真的搞砸了” 你做了什么?
-
宏:int EIEIO
“Computer bought the farm. 电脑买下了农场” 回家喝一杯温热的新鲜牛奶。
-
宏:int EGRATUITOUS
“Gratuitous error. 无端错误” 此错误代码没有任何用途。
-
宏:int EBADMSG
“Bad message. 坏消息”
-
宏:int EIDRM
“Identifier removed. 标识符已删除”
-
宏:int EMULTIHOP
“Multihop attempted. 尝试多跳”
-
宏:int ENODATA
“No data available. 无可用数据”
-
宏:int ENOLINK
“Link has been severed. 链接被切断了”
-
宏:int ENOMSG
“No message of desired type. 没有所需类型的消息”
-
宏:int ENOSR
“Out of streams resources. 流资源不足”
-
宏:int ENOSTR
“Device not a stream. 设备不是流”
-
宏:int EOVERFLOW
“Value too large for defined data type. 值对于定义的数据类型来说太大了”
-
宏:int EPROTO
“Protocol error. 协议错误”
-
宏:int ETIME
“Timer expired. 定时器超时”
-
宏:int ECANCELED
“Operation canceled. 操作取消” 异步操作在完成之前被取消。请参阅并行执行 I/O 操作。当您调用 aio_cancel 时,正常结果是受影响的操作完成并出现此错误;请参阅取消 AIO 操作。
-
宏:int EOWNERDEAD
“Owner died. 主人死了”
-
宏:int ENOTRECOVERABLE
“State not recoverable. 状态不可恢复”
以下错误代码由 Linux/i386 内核定义。它们尚未记录在案。
-
宏:int ERESTART
“Interrupted system call should be restarted. 应该重新启动中断的系统调用”
-
宏:int ECHRNG
“Channel number out of range. 频道号超出范围”
-
宏:int EL2NSYNC
“Level 2 not synchronized. 2级未同步”
-
宏:int EL3HLT
“Level 3 halted. 3级停止”
-
宏:int EL3RST
“Level 3 reset. 三级重置”
-
宏:int ELNRNG
“Link number out of range. 链接号码超出范围”
-
宏:int EUNATCH
“Protocol driver not attached. 未附加协议驱动程序”
-
宏:int ENOCSI
“No CSI structure available. 没有可用的 CSI 结构”
-
宏:int EL2HLT
“Level 2 halted. 2级停止”
-
宏:int EBADE
“Invalid exchange. 交换无效”
-
宏:int EBADR
“Invalid request descriptor. 请求描述符无效”
-
宏:int EXFULL
“Exchange full. 交换满了”
-
宏:int ENOANO
“No anode. 没有阳极”
-
宏:int EBADRQC
“Invalid request code. 请求代码无效”
-
宏:int EBADSLT
“Invalid slot. 无效的插槽”
-
宏:int EDEADLOCK
“File locking deadlock error. 文件锁定死锁错误”
-
宏:int EBFONT
“Bad font file format. 字体文件格式错误”
-
宏:int ENONET
“Machine is not on the network. 机器不在网络上”
-
宏:int ENOPKG
“Package not installed. 未安装软件包”
-
宏:int EADV
“Advertise error. 广告错误”
-
宏:int ESRMNT
“Srmount error. Srmount 错误”
-
宏:int ECOMM
“Communication error on send. 发送通信错误”
-
宏:int EDOTDOT
“RFS specific error. RFS 特定错误”
-
宏:int ENOTUNIQ
“Name not unique on network. 名称在网络上不是唯一的”
-
宏:int EBADFD
“File descriptor in bad state. 文件描述符处于错误状态”
-
宏:int EREMCHG
“Remote address changed. 远程地址已更改”
-
宏:int ELIBACC
“Can not access a needed shared library. 无法访问所需的共享库”
-
宏:int ELIBBAD
“Accessing a corrupted shared library. 访问损坏的共享库”
-
宏:int ELIBSCN
“.lib section in a.out corrupted. a.out 中的 .lib 部分已损坏”
-
宏:int ELIBMAX
“Attempting to link in too many shared libraries. 试图链接太多共享库”
-
宏:int ELIBEXEC
“Cannot exec a shared library directly. 无法直接执行共享库”
-
宏:int ESTRPIPE
“Streams pipe error. 流管道错误”
-
宏:int EUCLEAN
“Structure needs cleaning. 结构需要清洁”
-
宏:int ENOTNAM
“Not a XENIX named type file. 不是 XENIX 命名类型文件”
-
宏:int ENAVAIL
“No XENIX semaphores available. 没有可用的 XENIX 信号量”
-
宏:int EISNAM
“Is a named type file. 是一个命名类型文件”
-
宏:int EREMOTEIO
“Remote I/O error. 远程 I/O 错误”
-
宏:int ENOMEDIUM
“No medium found. 没有找到介质”
-
宏:int EMEDIUMTYPE
“Wrong medium type. 错误的媒体类型”
-
宏:int ENOKEY
“Required key not available. 所需的密钥不可用”
-
宏:int EKEYEXPIRED
“Key has expired. 密钥已过期”
-
宏:int EKEYREVOKED
“Key has been revoked. 密钥已被吊销”
-
宏:int EKEYREJECTED
“Key was rejected by service. 密钥被服务拒绝了”
-
宏:int ERFKILL
“Operation not possible due to RF-kill. 由于射频杀伤,无法进行操作”
-
宏:int EHWPISON
“Memory page has hardware error. 内存页有硬件错误”
2.3. 错误信息
Error Messages
该库具有旨在使您的程序以习惯格式报告有关库调用失败的信息性错误消息的函数和变量。函数 strerror 和 perror 为您提供给定错误代码的标准错误消息;变量 program_invocation_short_name 使您可以方便地访问遇到错误的程序的名称。
函数:char * strerror (int errnum)
Preliminary: | MT-Unsafe race:strerror | AS-Unsafe heap i18n | AC-Unsafe mem | See POSIX Safety Concepts.
strerror 函数将 errnum 参数指定的错误代码(请参阅检查错误)映射到描述性错误消息字符串。返回值是指向该字符串的指针。
errnum 的值通常来自变量 errno。
您不应修改 strerror 返回的字符串。此外,如果您对 strerror 进行后续调用,则该字符串可能会被覆盖。(但可以保证没有库函数会在你背后调用 strerror。)
函数 strerror 在 string.h 中声明。
函数:char * strerror_r (int errnum, char *buf, size_t n)
Preliminary: | MT-Safe | AS-Unsafe i18n | AC-Unsafe | See POSIX Safety Concepts.
strerror_r 函数的工作方式与 strerror 类似,但它不是在进程中所有线程共享的静态分配缓冲区中返回错误消息,而是返回线程的私有副本。这可能是一些永久的全局数据或用户提供的缓冲区中的消息字符串,该缓冲区从 buf 开始,长度为 n 字节。
最多写入 n 个字符(包括 NUL 字节),因此由用户选择足够大的缓冲区。
此函数应始终用于多线程程序,因为无法保证 strerror 返回的字符串确实属于当前线程的最后一次调用。
函数 strerror_r 是一个 GNU 扩展,它在 string.h 中声明。
函数:void perror (const char *message)
Preliminary: | MT-Safe race:stderr | AS-Unsafe corrupt i18n heap lock | AC-Unsafe corrupt lock mem fd | See POSIX Safety Concepts.
此函数将错误消息打印到流 stderr;请参阅标准流。stderr 的方向没有改变。
如果您使用空指针或空字符串的消息调用 perror,则 perror 只会打印与 errno 对应的错误消息,并添加一个尾随换行符。
如果您提供非空消息参数,则 perror 会在其输出前加上此字符串。它添加一个冒号和一个空格字符来将消息与对应于 errno 的错误字符串分开。
函数 perror 在 stdio.h 中声明。
函数:const char * strerrorname_np (int errnum)
| MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.
此函数返回描述错误 errnum 的名称,如果没有具有此值的已知常量(例如 EINVAL 的“EINVAL”),则返回 NULL。
这个函数是一个 GNU 扩展,在头文件 string.h 中声明。
函数:const char * strerrordesc_np (int errnum)
| MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.
如果没有具有此值的已知常量(例如 EINVAL 的“无效参数”),此函数返回描述错误 errnum 或 NULL 的消息。与 strerror 不同,返回的描述不被翻译。
这个函数是一个 GNU 扩展,在头文件 string.h 中声明。
strerror 和 perror 为任何给定的错误代码生成完全相同的消息;确切的文本因系统而异。使用 GNU C 库,消息相当短。没有多行消息或嵌入的换行符。每条错误消息都以大写字母开头,并且不包含任何终止标点符号。
许多不从终端读取输入的程序被设计为在任何系统调用失败时退出。按照惯例,来自此类程序的错误消息应以程序名称开头,无目录。您可以在变量 program_invocation_short_name 中找到该名称;完整的文件名存储在变量 program_invocation_name 中。
变量:char * program_invocation_name
该变量的值是用于调用在当前进程中运行的程序的名称。它与 argv[0] 相同。请注意,这不一定是有用的文件名;通常它不包含目录名称。请参阅程序参数。
该变量是 GNU 扩展,在 errno.h 中声明。
变量:char * program_invocation_short_name
此变量的值是用于调用在当前进程中运行的程序的名称,删除了目录名称。(也就是说,它等于 program_invocation_name 减去最后一个斜线之前的所有内容,如果有的话。)
该变量是 GNU 扩展,在 errno.h 中声明。
库初始化代码在调用 main 之前设置这两个变量。
可移植性说明:如果您希望您的程序使用非 GNU 库,您必须将 argv[0] 的值保存在 main 中,然后自己剥离目录名称。我们添加了这些扩展,以便编写独立的错误报告子例程,这些子例程不需要 main 的显式合作。
这是一个示例,显示如何处理无法正确打开文件的失败。函数 open_sesame 尝试打开指定文件进行读取,如果成功则返回一个流。如果由于某种原因无法打开文件,fopen 库函数将返回一个空指针。在这种情况下,open_sesame 使用 strerror 函数构造适当的错误消息,并终止程序。如果我们要在将错误代码传递给 strerror 之前进行一些其他库调用,我们必须将其保存在局部变量中,因为其他库函数可能会同时覆盖 errno。
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *
open_sesame (char *name)
{
FILE *stream;
errno = 0;
stream = fopen (name, "r");
if (stream == NULL)
{
fprintf (stderr, "%s: Couldn't open file %s; %s\n",
program_invocation_short_name, name, strerror (errno));
exit (EXIT_FAILURE);
}
else
return stream;
}
使用 perror 的优点是该函数是可移植的,并且在所有实现 ISO C 的系统上都可用。但是 perror 生成的文本通常不是我们想要的,并且没有办法扩展或更改 perror 所做的事情。例如,GNU 编码标准要求错误消息以程序名开头,读取某些输入文件的程序应提供有关输入文件名和行号的信息,以防在读取文件时遇到错误。对于这些情况,有两个功能可用,它们在整个 GNU 项目中被广泛使用。这些函数在 error.h 中声明。
函数:void error (int status , int errnum , const char * format , ...)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap i18n | AC-Safe | See POSIX Safety Concepts.
error 函数可用于报告程序执行期间的一般问题。format 参数是一个格式字符串,就像给 printf 系列函数的那些一样。格式所需的参数可以跟在格式参数之后。就像 perror 一样,error 也可以以文本形式报告错误代码。但与 perror 不同,错误值在 errnum 参数中显式传递给函数。这消除了上面提到的错误报告函数必须在导致错误的函数之后立即调用的问题,否则 errno 可能具有不同的值。
error 首先打印程序名称。如果应用程序定义了一个全局变量 error_print_progname 并将其指向一个函数,则该函数将被调用以打印程序名称。否则使用来自全局变量 program_name 的字符串。程序名称后跟一个冒号和一个空格,然后是格式字符串产生的输出。如果 errnum 参数非零,则格式字符串输出后跟一个冒号和一个空格,然后是错误代码 errnum 的错误消息。在任何情况下,输出都会以换行符终止。
输出被定向到 stderr 流。如果 stderr 在调用之前没有定向,那么它之后将是窄定向的。
除非状态参数具有非零值,否则该函数将返回。在这种情况下,函数将使用其参数的状态值调用 exit,因此永远不会返回。如果错误返回,全局变量 error_message_count 会加一以跟踪报告的错误数。
函数:void error_at_line (int status , int errnum , const char * fname , unsigned int lineno , const char * format , ...)
Preliminary: | MT-Unsafe race:error_at_line/error_one_per_line locale | AS-Unsafe corrupt heap i18n | AC-Unsafe corrupt/error_one_per_line | See POSIX Safety Concepts.
error_at_line 函数与 error 函数非常相似。唯一的区别是附加参数 fname 和 lineno。其他参数的处理与 error 的处理相同,只是在程序名和格式字符串生成的字符串之间插入了附加文本。
程序名后面直接跟一个冒号,后面跟fname指向的文件名,再跟一个冒号,打印出lineno的值。
这个额外的输出当然是用来定位输入文件(如编程语言源代码文件等)中的错误。
如果全局变量 error_one_per_line 设置为非零值,error_at_line 将避免打印同一文件和同一行的连续消息。不直接跟随彼此的重复不会被捕获。
就像错误一样,此函数仅在状态为零时返回。否则用非零值调用 exit。如果错误返回,全局变量 error_message_count 会加一以跟踪报告的错误数。
如上所述,可以通过定义名为 error_print_progname 的变量来自定义 error 和 error_at_line 函数。
变量:void (*error_print_progname) (void)
如果 error_print_progname 变量定义为非零值,则指向的函数由 error 或 error_at_line 调用。预计会打印程序名称或执行类似有用的操作。
该函数预计将打印到 stderr 流,并且必须能够处理流具有的任何方向。该变量是全局的并且由所有线程共享。
变量:unsigned int error_message_count
每当函数 error 或 error_at_line 之一返回时,error_message_count 变量就会递增。该变量是全局的并且由所有线程共享。
变量:int error_one_per_line
error_one_per_line 变量仅影响 error_at_line。通常,error_at_line 函数会为每次调用创建输出。如果 error_one_per_line 设置为非零值,error_at_line 会跟踪报告错误的最后一个文件名和行号,并避免直接跟踪同一文件和行的消息。这个变量是全局的并且被所有线程共享。
读取一些输入文件并在其中报告错误的程序可能如下所示:
{
char *line = NULL;
size_t len = 0;
unsigned int lineno = 0;
error_message_count = 0;
while (! feof_unlocked (fp))
{
ssize_t n = getline (&line, &len, fp);
if (n <= 0)
/* End of file or error. */
break;
++lineno;
/* Process the line. */
…
if (Detect error in line)
error_at_line (0, errval, filename, lineno,
"some error text %s", some_variable);
}
if (error_message_count != 0)
error (EXIT_FAILURE, 0, "%u errors found", error_message_count);
}
error 和 error_at_line 显然是选择的函数,使程序员能够编写遵循 GNU 编码标准的应用程序。GNU C 库还包含在 BSD 中用于相同目的的函数。这些函数在 err.h 中声明。通常建议不要使用这些功能。包含它们只是为了兼容性。
函数:void warn (const char * format , ...)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap i18n | AC-Unsafe corrupt lock mem | See POSIX Safety Concepts.
warn 函数大致相当于这样的调用
error (0, errno, format, the parameters)
除了不使用全局变量错误尊重(respectes)和修改。
函数:void vwarn (const char *format, va_list ap)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap i18n | AC-Unsafe corrupt lock mem | See POSIX Safety Concepts.
vwarn 函数和 warn 一样,只是用于处理格式字符串格式的参数是作为 va_list 类型的值传入的。
函数:void warnx (const char *format, ...)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap | AC-Unsafe corrupt lock mem | See POSIX Safety Concepts.
warnx 函数大致相当于这样的调用
error (0, 0, format, the parameters)
除了不使用全局变量错误尊重和修改。警告的不同之处在于不打印错误号字符串。
函数:void vwarnx (const char *format, va_list ap)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap | AC-Unsafe corrupt lock mem | See POSIX Safety Concepts.
vwarnx 函数与 warnx 类似,只是用于处理格式字符串格式的参数作为 va_list 类型的值传入。
函数:void err (int status, const char *format, ...)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap i18n | AC-Unsafe corrupt lock mem | See POSIX Safety Concepts.
err 函数大致相当于这样的调用
error (status, errno, format, the parameters)
除了不使用全局变量 error 和 modify 并且即使状态为零,程序也会退出。
函数:void verr (int status, const char *format, va_list ap)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap i18n | AC-Unsafe corrupt lock mem | See POSIX Safety Concepts.
verr 函数就像 err 一样,只是用于处理格式字符串格式的参数作为 va_list 类型的值传入。
函数:void errx (int status, const char *format, ...)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap | AC-Unsafe corrupt lock mem | See POSIX Safety Concepts.
errx 函数大致相当于这样的调用
error (status, 0, format, the parameters)
除了不使用全局变量 error 和 modify 并且即使状态为零,程序也会退出。与 err 的区别在于不打印错误号字符串。
函数:void verrx (int status, const char *format, va_list ap)
Preliminary: | MT-Safe locale | AS-Unsafe corrupt heap | AC-Unsafe corrupt lock mem | See POSIX Safety Concepts.
verrx 函数就像 errx 一样,只是用于处理格式字符串格式的参数作为 va_list 类型的值传入。