C free()是否设置了errno?

C free()是否设置了errno?,c,linux,memory-management,C,Linux,Memory Management,如果buf是malloc()分配的字符缓冲区,free(buf)set/reseterrno 假设我想将缓冲区写入一个文件,然后释放它,因为我不再需要它了 假设代码的错误策略是在出现错误时返回-1 这是在不泄漏内存的情况下写出缓冲区和错误检查的正确方法吗 fputs(buf, somefile); free(buf); if (errno) return -1; 还是我需要考虑自由可能设置ErnNO,如… fputs(buf, somefile); if (errno){ free(

如果
buf
malloc()
分配的字符缓冲区,
free(buf)
set/reset
errno

假设我想将缓冲区写入一个文件,然后释放它,因为我不再需要它了

假设代码的错误策略是在出现错误时返回-1

这是在不泄漏内存的情况下写出缓冲区和错误检查的正确方法吗

fputs(buf, somefile);
free(buf);
if (errno) return -1;

还是我需要考虑自由可能设置ErnNO,如…

fputs(buf, somefile);
if (errno){ 
    free(buf);
    return -1;
}
free(buf);
或者,恐怖的恐怖

do { 
  fputs(buf, somefile);
  int save_errno = errno;
  free(buf);
  errno = save_errno;
  if (errno) return -1;
} while(0);  
如果块的使用允许本地存储错误存在于需要重用的不同位置

所有这些似乎都取决于free()是否设置了errno

这也是
malloc()
等的手册页。它提到
malloc()
设置errno,但不是
free()

没有提到free()是否设置errno

因此,我编写了一个简短的程序来强制执行写入错误,这样我就可以查看free()是否重置了errno,但它没有。我想知道我是否应该依赖这个结果以及free()如此重要以至于“当然它不会设置errno”这一事实

#查看free()是否在错误写入时重置errno
#包括
#包括
#包括
#包括
int main(int argc,字符**argv)
{
char*buf=malloc(256);
snprintf(buf,256,“%s\n”,“你好,世界!”);
文件*坏文件;
badfile=fopen(“/dev/null”,“r”);
FPUT(buf、badfile);
免费(buf);
printf(“%d\n”,错误号);
printf(“%s\n”,strerror(errno));
}
POSIX没有定义设置
errno
(尽管POSIX目前没有禁止它,所以一个实现可能会这样做-有关更多详细信息,请参阅)。但这与你的担心无关

检查错误的方式是不正确的。您应该检查
fputs
的返回值,并检查它是否小于
0
。如果是,那么您可以检查
errno
,找出导致故障的原因,但这是可选的(应该在调用任何其他函数之前完成)

所以,像这样的事情应该可以做到:

int result = fputs(buf, somefile);
/* optionally read errno here if result < 0 (before the free call) */
free(buf);
return (result < 0) ? -1 : 0;
int result=fputs(buf,somefile);
/*如果结果<0(在自由调用之前),可以选择在此处读取errno*/
免费(buf);
返回(结果<0)-1 : 0;

如果引用没有说明函数在失败时在
errno
中返回错误代码,则不会

errno
设置为错误代码的函数(几乎)总是以另一种方式发出信号,表示
errno
包含当前错误代码-内存分配函数返回
NULL
,许多其他函数返回零或负数,依此类推。
如果这些函数成功,则不需要以任何方式修改
errno
,而且通常不会

您通常无法检查
errno
以确定是否出现了问题;它只用于在您知道发生错误后检索更多信息

最后一条规则的一个例外是strto{l,d,ul}系列,但第一段同样适用于这些规则。

而且它们也不一定设置
errno
,除非它们失败,所以您需要先清除它,否则它可能包含一个过时的错误代码。

在C标准中对
free
的描述中没有提到
errno
。因此,您可能不依赖此功能

根据C标准(7.5错误

3…如果使用了errno,则无论是否存在错误,库函数调用都可以将errno的值设置为非零 本节中的功能描述中未记录 国际标准


正如我前面所说,C标准中的
free
说明中没有记录
errno
的使用。

符合POSIX标准的
free
可能会在今天设置
errno
,但将来会变得更好。详情:

  • 定义如下:
  • POSIX.1-2008本卷中的任何函数均不得将errno设置为0。成功调用函数后的errno设置未指定,除非该函数的描述指定不应修改errno

  • 本身的定义没有指定
    free
    errno
    的作用
  • 这意味着兼容的
    free
    实现永远不会将
    errno
    重置为0。但它可能会也可能不会将其设置为非零值

    但是,当通过有效输入时,规范的第8版(正在进行的工作)将被删除


    已准备好遵守此新要求。

    您可以使用RAII释放malloced内存,并检查FPUT的返回值。这就是格雷斯密码

    //if malloc successfully
    AutoFree af(buf);
    if (fputs(buf, somefile)) {
    LOG("something err:%s", strerror(errno));
    }
    return 0;
    

    A.此外,
    errno
    的值在调用未显式设置的函数后未定义,其中包括未失败的函数调用。换句话说,除非上一次调用显式失败,否则不要选中
    errno
    free
    的“误用”与尝试两次释放同一指针一样,不必崩溃,它只是未定义。虽然在许多情况下未定义的行为会导致崩溃,但您不需要求助于
    do{…}while(0)构造,您还可以使用简单的大括号创建块
    {…}
    。在什么情况下,传递有效输入时可能会释放设置errno?@Random832,这取决于实现。也许有些人不碰
    errno
    。查看glibc的bug报告(但要清楚这还不是bug,因为POSIX还没有被修改),我在回答的最后一行链接到,详细了解glibc的
    free
    @Random832实现中会发生什么,想象一个malloc/free实现在可能的情况下尝试收缩堆,使用适用于底层操作系统的系统调用,例如mmap()、sbrk()等。如果这些系统调用失败,errno将
    //if malloc successfully
    AutoFree af(buf);
    if (fputs(buf, somefile)) {
    LOG("something err:%s", strerror(errno));
    }
    return 0;