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

时间:2018-03-17 19:26:59

标签: c++ c crypt unistd.h

我已经编写并运行以下代码:

#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;
}

errno的初始值为0,但在调用crypt()函数后,它设置为2 ENOENT

这是输出:

errno = 0
abtAunjzvWWRQ
errno = 2

1 个答案:

答案 0 :(得分:3)

以下是C标准对errno所说的内容(§7.5,第3段,强调补充。)

  

初始线程中errno的值在程序启动时为零   (其他线程中errno的初始值是不确定的   值),但永远不会被任何库函数设置为零。 价值   可以通过库函数调用将errno设置为非零,无论是否   如果没有记录errno的使用,则不会出现错误   在本国际标准中对功能的描述中。

这是Posix says(再次强调添加)的部分内容:

errno的值只有在函数的返回值表示有效时才应进行检查。...此POSIX.1-2008卷中的任何函数都不应将errno设置为0。 成功调用函数后errno的设置未指定,除非该函数的描述指定不应修改errno

crypt是Posix函数(由其在unistd.h中的存在表示)。该描述未指定不应修改errno。所以它可能是,它是。

简而言之,从不尝试使用errno的值,除非函数已明确报告错误并记录该函数以设置errno。在这种情况下,请确保在调用该函数后立即使用它(或保存其值),并在执行可能设置errno的任何其他操作之前(包括使用iostreams和{ {1}})。

这可能在孤立中看起来有点奇怪,但它实际上非常有意义。例如,考虑一个需要查询配置文件的函数(如果存在)。它将包括类似的代码:

cstdio

如果配置文件不存在,则不会被使用。没问题。但FILE* config = fopen(configFileName, "r"); if (config) { /* Read the file */ } else { /* Set default values */ } 可能已由errno失败设置{/ 1}}。

这种事情在库函数中很常见,它们在第一次调用时执行初始化。如果不是这个规定,任何调用另一个库函数的库函数都必须在开始之前小心保存fopen,然后在结束时将其恢复,除非报告实际错误。我敢打赌你的功能不会这样做:) - 我当然不会。它很狡猾,容易出错。实际采用的约定更好,更可审计:errno仅在函数明确报告错误时才有效。