问题
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 oferrno
in other threads is an indeterminate value), but is never set to zero by any library function. The value oferrno
may be set to nonzero by a library function call whether or not there is an error, provided the use oferrno
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