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()假设它是空终止.
防止这种情况的最佳方法是什么?
防止这种情况的最佳方法是什么?
很简单,不要给它一个非空终止字符串.除了学术问题,您可以控制自己编写的代码.你不必以各种可能的方式防止自己破坏项目,你只需要不要破坏自己.
如果每个人都检查并仔细检查代码中的所有内容,那么性能损失就会令人难以置信 这是为什么fopen不这样做的原因.
因此,如果它返回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)