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

孤者浪人 提交于 2019-12-25 00:14:26

问题


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).

Here is the output:

errno = 0
abtAunjzvWWRQ
errno = 2

回答1:


Here's what the C standard says about errno (§7.5, para 3, emphasis added.)

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. 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.

And here's (part of) what Posix says (again, emphasis added):

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.

crypt is a Posix function (as indicated by its presence in unistd.h). The description does not specify that errno shall not be modified. 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. 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).

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.

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. 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.



来源:https://stackoverflow.com/questions/49341043/why-does-a-call-to-the-crypt-function-from-unistd-h-set-the-errno-to-enoent

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!