我该设置errno吗?

49

我正在编写一个导出类似于sendrecv接口的模块。

由于这些函数应分别返回发送和接收字节数,因此我不能像通常那样进行适当的错误管理(即使用枚举并返回助记值)。

在这种情况下,我应该像标准库一样设置errno吗?如果是这样,由于errno是线程特定的,是否有特定的写入方式,还是我可以简单地将值赋给它?

编辑:实验发现通过赋值设置errno是有效的。但是:这对任何系统都是安全和可移植的吗?


5
关于 errno 和 C 标准,如果你想了解更多信息,请访问 https://dev59.com/RWcs5IYBdhLWcg3wUCYI (注:该链接为英文网站)。 - Nemo
6个回答

41

这篇文章有点旧,但是errno - 手册第三章说,您可以直接将值赋予它,即使它是一个宏,它也会是线程本地的。


26

在许多情况下,调用一些库函数时只有在将 errno 设置为零后才能可靠地检测到错误,所以不仅可以设置 errno,而且应该这样做。请参见示例中的 strtol

来自 strtol 的 POSIX 规范:

[CX] [选项起始] 如果成功,则 strtol() 函数不会更改 errno 的设置。

由于在发生错误时返回 0、{LONG_MIN} 或 {LLONG_MIN} 和 {LONG_MAX} 或 {LLONG_MAX},而这些值也是成功的有效返回值,因此希望检查错误情况的应用程序应将 errno 设置为0,然后调用 strtol() 或 strtoll(),然后检查 errno。[选项结束]


10

实际上,你很可能可以进行“正确”的(正如你所说的)错误管理,因为你返回了一个int

只需对读取或写入的字节数使用非负值,并对错误代码使用负值。你不必局限于 -1

enum myerrors {
    ERR_NO_MEMORY    = -1,
    ERR_BAD_ARGS     = -2,
    ERR_CPU_EXPLODED = -3,
    // and so on
};

然而,以你想要的方式设置errno是有效的。标准规定errno会扩展为一个可修改的左值,这意味着你可以对其进行设置。参见C1x/n1425, 7.5 Errors <errno.h>

... 以及errno扩展为一个可修改的左值,类型为int,其值由几个库函数设置为正数错误号。


6
你可以直接给errno赋值,但请记住还有其他方法来表示错误,具体取决于你的情况,可能更合适:
  1. 不要返回读取的字节数,而是使用类型为int *(或size_t *或您使用的任何其他类型)的输出参数。然后可以返回错误代码。
  2. 假设您的返回类型是有符号类型,并且负的发送或接收字节数没有意义,请使用负值来表示相应的错误条件。

errno 被 POSIX 中几乎所有的函数使用(除了返回错误代码和一些奇怪的例外),而不仅仅是低级别的东西。 - R.. GitHub STOP HELPING ICE

3

是的,你可以对它进行赋值,并且这个赋值操作是线程安全的。请参考Is errno thread-safe?


2

我更感兴趣的是分配它的技术细节,但我没有预料到会出现这种可移植性问题! :) - Dacav
1
@Dacav - 我认为没有特殊的设置方式...你可以直接赋值...如果可能的话,我会使用在 errno.h 中定义的枚举值。 - prelic
3
那个列表不是完整的,标准规定必须包括EILSEQ - paxdiablo
2
@prelic 我对设置它的问题来源于它是使用宏实现的线程特定全局变量。加1给枚举值(如果您想要有意义的值,这当然是必需的!) - Dacav
@R.. 随着我阅读的深入,我发现...不确定那篇文章是否过时或者是错误的。 - prelic
POSIX是与ISO C分开的标准。虽然ISO C没有定义许多errno值,但它确实定义了第三个值“EILSEQ”。 - R.. GitHub STOP HELPING ICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接