Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C sprintf()的输入和输出字符串是否相同?_C_Printf - Fatal编程技术网

C sprintf()的输入和输出字符串是否相同?

C sprintf()的输入和输出字符串是否相同?,c,printf,C,Printf,我在过去的代码中多次使用这种约定: strcpy ( cTmpA, "hello" ); sprintf ( cTmpA, "%s world", cTmpA ); 最近,我将我的遗留C编译器切换到VisualStudio2005,发现上面的代码导致了一个乱码字符串。然后我想到,可能sprintf()的行为没有严格定义,其中一个输入与输出字符串匹配 上述代码是否有效K&R C?如果没有,我如何在代码中找到发生这种类型的sprintf()调用的所有位置?大多数sprintf()的实现不会复制格式

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

strcpy ( cTmpA, "hello" );
sprintf ( cTmpA, "%s world", cTmpA );
最近,我将我的遗留C编译器切换到VisualStudio2005,发现上面的代码导致了一个乱码字符串。然后我想到,可能sprintf()的行为没有严格定义,其中一个输入与输出字符串匹配


上述代码是否有效K&R C?如果没有,我如何在代码中找到发生这种类型的sprintf()调用的所有位置?

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

您应该真正使用
snprintf()
,它可以防止缓冲区溢出

要查找所有调用,请将
#define sprintf++
放入一个公共头中,查找并重新编译所有源代码。这将为您提供一个错误列表以及文件名和行号:)或使用IDE的递归搜索“n”替换

如果要将此列表精简为两个参数使用相同指针的列表,请使用以下宏:

#define sprintf(output,format,...) check_sprintf(__FILE__,__LINE__,output,format,....)
请注意,并非所有编译器都支持带有varargs的宏。然后定义一个新函数
check\u 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()
来获取第一个参数并在比较中使用它。

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

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


重复使用宏替换来发现发生这种情况的地方的好主意。我想到了这一点,但想不出一种方法来制作一个宏,只有当输出也是输入之一时才会导致编译时错误。重新定义sprintf()的问题是,这只会在运行时出现,而我的项目足够大,如果没有某种类型的自动单元测试,我永远无法找到每个代码路径。随着时间的推移,你会发现所有地方,因为程序很难崩溃(而不是默默地产生错误数据)。因此,现在就从单元测试开始,修复尽可能多的地方,然后在出现bug报告时修复其余的地方。