我有一个使用sprintf的简单代码
#include <stdio.h>
int main()
{
char str_src [1024]={"Hello"};
sprintf(str_src,"%s%s",str_src,"hiiiiiiiiiii");
printf("result = %s",str_src);
}
当我编译时,我得到了正确的结果:
result = Hellohiiiiiiiiiii
但是由于sprintf不安全,我决定将其更改为snprintf。我觉得这很简单。我将sprintf更改为snprintf,如下所示
snprintf(str_src,1024,"%s%s",str_src,"hiiiiiiiiiii");
现在如果我编译并运行代码,我会得到不同的结果
result = hiiiiiiiiiii
如果我使用str_src作为第四个参数(作为%s的值),我将面临这个问题。令人惊讶的是为什么snprintf的行为与sprintf不同?
答案 0 :(得分:11)
未定义的行为使用相同的缓冲区作为目标和源。
从C11规范(7.21.6.6/2):
如果在重叠的对象之间进行复制,则行为未定义。
对于snprintf
(7.21.6.5/2)以及va_list
变体也是如此。
不幸的是,它在运行代码时很常见,但它并不能真正依赖它。
答案 1 :(得分:4)
来自sprintf
联机帮助页:
C99和POSIX.1-2001指定在调用时结果未定义 到sprintf(),snprintf(),vsprintf()或vsnprintf()会导致 复制发生在重叠的对象之间(例如,如果 目标字符串数组和提供的输入参数之一引用 相同的缓冲区)。见注释。
这个问题真的没有答案,因为你的代码有不确定的行为。
答案 2 :(得分:0)
不,在这两种情况下都会得到完全随意的结果,因为它是未定义的行为。其中一个发生就是你想要的。您可能在不同的计算机上得到不同的结果对于它的价值,它可能会格式化您的硬盘并仍然是正确的行为。只是不要使用重叠的来源和目的地。