简体   繁体   English

为什么从unistd.h调用crypt()函数将errno设置为ENOENT?

[英]Why does a call to the crypt() function from unistd.h set the errno to ENOENT?

I have written and run the following code: 我已经编写并运行以下代码:

#define _XOPEN_SOURCE
#include <iostream>
#include <unistd.h>

int main()
{
  std::cout << "errno = " << errno << std::endl;
  std::cout << crypt("sometext", "ab") << std::endl;
  std::cout << "errno = " << errno <<std:: endl;

  return 0;
}

The initial value of errno was 0 , but after a call to the crypt() function it was set to 2 ( ENOENT ). errno的初始值为0 ,但是在调用crypt()函数后,其设置为2ENOENT )。

Here is the output: 这是输出:

errno = 0
abtAunjzvWWRQ
errno = 2

Here's what the C standard says about errno (§7.5, para 3, emphasis added.) 这是C标准关于errno (第7.5节,第3段,重点已添加。)

The value of errno in the initial thread is zero at program startup (the initial value of errno in other threads is an indeterminate value), but is never set to zero by any library function. 程序启动时,初始线程中errno的值为零(其他线程中errno的初始值为不确定的值),但是任何库函数都不会将其设置为零。 The value of errno may be set to nonzero by a library function call whether or not there is an error , provided the use of errno is not documented in the description of the function in this International Standard. 无论是否存在错误都可以通过库函数调用将errno的值设置为非零 ,前提是在此国际标准的函数描述中未记录errno的使用。

And here's (part of) what Posix says (again, emphasis added): 这是Posix说的(部分)(再次强调):

The value of errno should only be examined when it is indicated to be valid by a function's return value.… No function in this volume of POSIX.1-2008 shall set errno to 0. The setting of errno after a successful call to a function is unspecified unless the description of that function specifies that errno shall not be modified. errno时,则说明是由函数的返回值有效的只应检查......在这卷POSIX.1-2008的无功能将设置errno为0 的设置errno成功调用函数后除非该函数的说明指定errno不得修改,否则指定。

crypt is a Posix function (as indicated by its presence in unistd.h ). crypt是Posix函数(如unistd.h存在所示)。 The description does not specify that errno shall not be modified. 该描述未指定errno不应被修改。 So it may be and it was. 可能是这样,过去是。

In short, never attempt to use the value of errno unless a function has clearly reported an error and that function is documented to set errno . 简而言之,除非函数明确报告了错误并且已记录该函数设置errno ,否则切勿尝试使用errno的值。 And in that case, make sure you use it (or save its value) immediately after the call to that function, and before doing anything else which might set errno (which includes the use of iostreams and cstdio ). 在这种情况下,请确保在调用该函数之后,执行可能设置errno任何其他操作(包括使用iostreamscstdio )之前立即使用它(或保存其值)。

That might all seem a bit odd in isolation, but it actually makes perfect sense. 孤立地看这似乎有些奇怪,但实际上是很合理的。 Consider, for example, a function which needs to consult a configuration file, if one exists. 例如,考虑一个需要查阅配置文件的功能(如果存在)。 It's going to include code something like: 它将包含类似以下的代码:

FILE* config = fopen(configFileName, "r");
if (config) { /* Read the file */ }
else { /* Set default values */ }

If the config file doesn't exist, it simply doesn't get used. 如果配置文件不存在,则根本不会使用它。 No problem. 没问题。 But errno may well have been set by the fopen failure. 但是errno可能是由fopen失败引起的。

This sort of thing is pretty common in library functions, which perform initialization on the first call. 这种事情在库函数中很常见,库函数在第一次调用时执行初始化。 If it weren't for this provision, any library function which called another library function would have to carefully save errno before it started and then restore it at the end, unless an actual error was being reported. 如果不是用于此规定,则调用另一个库函数的任何库函数都必须在启动之前仔细保存errno ,然后在结束时将其还原,除非已报告实际错误。 I'll bet your functions don't do that :) -- mine certainly don't. 我敢打赌,您的功能不会这样做:)-我的当然不会。 It's fiddly and error-prone. 这很容易出错。 Better and more auditable is the convention actually adopted: errno is only valid if the function definitely reported an error. 实际采用的约定更好,更易于审核: errno仅在函数明确报告错误时才有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM