sprintf()的输入和输出字符串可以相同吗?

时间:2009-12-29 08:38:05

标签: c printf

我过去在代码中多次使用过这种类型的约定:

strcpy ( cTmpA, "hello" );
sprintf ( cTmpA, "%s world", cTmpA );

最近我将我的旧C编译器切换到Visual Studio 2005,发现我得到了一个由上面的代码产生的乱码字符串。然后我想到,sprintf()的行为可能没有严格定义,其中一个输入与输出字符串匹配。

以上代码是否有效K& R C?如果没有,我如何找到代码中发生sprintf()调用的所有地方?

2 个答案:

答案 0 :(得分:20)

虽然它是有效的K& R C,但您可能想要知道它是否有效POSIX - 请参阅sprintf Specification。我们读到:

  

如果由于调用sprintf()或snprintf()而重叠的对象之间发生复制,则结果是未定义的。

答案 1 :(得分:9)

sprintf()的大多数实现都不复制格式字符串,而是在您传递的字符串中使用指针。如果格式和输出指向同一个内存,那将导致奇怪的结果。

你应该使用snprintf()来保护你免受缓冲区溢出。

要查找所有呼叫,请将#define sprintf +++放入公共标头查找并重新编译所有源。这应该给你一个错误列表以及文件名和行号:)或者使用你的IDE的递归搜索。

如果要将此列表修剪为两个参数使用相同指针的列表,请使用此宏:

#define sprintf(output,format,...) check_sprintf(__FILE__,__LINE__,output,format,....)

请注意,并非所有编译器都支持使用varargs的宏。然后定义一个新函数check_sprintf

int check_sprintf (char*filename,int line,char*output,char*format,...) {
    va_list args;
    int len;

    if(output==format) {
        fprintf(stderr,
             "Output and format are the same at %s:%d", filename, line);
             abort();
    }

    va_start (args, format);
    len = vsprintf (output, format, args);
    va_end (args);

    return len;   
}

[编辑]我刚看到你在谈论输出和第一个参数。您可以重用上面的代码并调用va_arg()来获取第一个参数并在比较中使用它。