如何避免使用C中非空终止的缓冲区调用fopen()?

Sed*_*ter 3 c string null fopen stdio

我们来看看这个例子:

static FILE *open_file(const char *file_path)
{
    char buf[80];
    size_t n = snprintf(buf, sizeof (buf), "%s", file_path);
    assert(n < sizeof (buf));
    return fopen(buf, "r");
}
Run Code Online (Sandbox Code Playgroud)

在这里,它assert()是一个接一个.从联机帮助页snprintf:

"成功返回后,这些函数返回打印的字符数(不包括用于结束输出到字符串的空字节)."

因此,如果它返回80,则字符串将填充缓冲区,并且不会被\ 0终止.这将导致问题,因为fopen()假设它是空终止.

防止这种情况的最佳方法是什么?

Bli*_*ndy 5

防止这种情况的最佳方法是什么?

很简单,不要给它一个非空终止字符串.除了学术问题,您可以控制自己编写的代码.你不必以各种可能的方式防止自己破坏项目,你只需要不要破坏自己.

如果每个人都检查并仔细检查代码中的所有内容,那么性能损失就会令人难以置信 这是为什么fopen不这样做的原因.


das*_*ght 5

因此,如果它返回80,那么字符串将填充缓冲区,并且不会被终止 \0

这是不正确的:无论你传递什么,字符串都将以空值终止file_path.显然,字符串将被切断sizeof(buf)-1.

请注意,snprintf也可以返回80以上的数字.这意味着您要打印的字符串比您提供的缓冲区长.

防止这种情况的最佳方法是什么?

您已经这样做了:assert不需要防止未终止的字符串.您可以使用返回值来确定是否发生了截断,并传递更大的缓冲区来补偿:

// Figure out the size
size_t n = snprintf(NULL, 0, "%s", file_path);
// Allocate the buffer and print into it
char *tmpBuf = malloc(n+1);
snprintf(tmpBuf, n+1, "%s", file_path);
// Prepare the file to return
FILE *res = fopen(tmpBuf, "r");
// Free the temporary buffer
free(tmpBuf);
return res;
Run Code Online (Sandbox Code Playgroud)

  • OP的问题和代码没有任何意义.您的新代码向他们展示了如何将任意长度的字符串复制到临时缓冲区中,但有什么意义呢?代码`return fopen(file_path,"r");`会更好地完成相同的结果. (2认同)
  • @EricPostpischil这绝对是真的.我的假设是OP的真实代码使用更复杂的格式字符串,需要打印更多数据.否则,使用`snprintf`进行整个练习是没有意义的. (2认同)
  • 如果是这种假设,那么我们应该向OP展示如何使用`snprintf(NULL,0,...);`,然后是`malloc`,然后是`snprintf(buffer,...)`,依此类推. (2认同)