为什么当我们使用相同的源和目标时,sprintf和snprintf的行为是不同的?

时间:2013-10-21 09:00:22

标签: c printf

我有一个使用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不同?

3 个答案:

答案 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)

不,在这两种情况下都会得到完全随意的结果,因为它是未定义的行为。其中一个发生就是你想要的。您可能在不同的计算机上得到不同的结果对于它的价值,它可能会格式化您的硬盘并仍然是正确的行为。只是不要使用重叠的来源和目的地。