2016-02-27 160 views
1

我已阅读帖子sprintf format specifier replace by nothing和其他相关,但没有看到具体解决这个问题。sprintf()是否需要格式说明符才能正常工作?

直到今天,我从来没有见过sprintf只用了2个参数。
我的系统使用sprintf()原型为:

int sprintf (char Target_String[], const char Format_String[], ...); 

虽然有一些遗留代码,我碰到这个跑工作:(简化图)

char toStr[30]; 
char fromStr[]={"this is the in string"}; 
sprintf(toStr, fromStr); 

我的原型的解释是,第二参数应由const char[]组成,并接受标准ansi C格式说明符such as these

但上面的例子似乎工作得很好,字符串fromStr作为第二个参数。
这是纯粹的未定义的行为,这是行之有效的?或者这种用法是完全合法的吗?

我正在使用C99编译器在Windows 7上工作。

+0

出于不同的原因,我想说的代码是附近的一个错误 - 我期望'字符fromStr [] = {“this is in string”};'应该是'char fromStr [] =“这是字符串”;'(no'{}')。代码确实编译,因为我确信OP的意图,但对我来说,它看起来像'char fromStr [] = {“这是在字符串”};'应该建立一个数组1'char'的指针值转换为一个'char'。我猜这是对的,但看起来错了 – chux

+0

@chux - 有趣的。我正在寻找同样的道路,试图发现哪些失败模式,如果有的话我可以找到。 (类似于_format字符串attack_,在下面的评论中提到)。我尝试用'= {“%这是在字符串”};'中出现与_unknown specifier_错误,然后再用'= {“%cthis是字符串”};',这是因为%c是一个已知的说明符,用_参数不足_出错。这两者似乎都支持下面答案的真相。至于使用'{“...”};'方括号,它们不会对我造成任何问题。 – ryyker

回答

1

您正在观察的行为是正确的,格式字符串不需要具有任何转换说明符。在这种情况下,由...表示的可变长度参数列表的长度为零。这是完全合法的,虽然它比它的等效

strcpy(toStr, fromStr); 
+1

@ryyker为什么像'sprintf'会失败的两个原因是目标缓冲区长度不足,或者源未正确终止。不过,这两种情况都会导致'strcpy'失败。 – dasblinkenlight

+0

您应该确保在所有这些sprintfs和strcpys中没有缓冲区溢出。最好使用这些函数的** n **变体。 – BitWhistler

1

这是完全合法的代码肯定是低效率的,但

  1. 如果你只是想复制一个字符串,可以使用strcpy()代替。
  2. 如果您正在处理用户输入,那么您可能会使自己容易受到format string attack的影响。
1

简介为sprintf是:

int sprintf(char *str, const char *format, ...); 

这意味着2个参数是合法的选项。

1

它的工作原理是因为您没有其他参数(即没有控制格式%)可以打印。

这是没有第二个参数没有区别比printf

int printf (const char * format, ...); 

,如果你没有任何第二个参数它也适用:

printf(fromStr); 
2

完全合法的。可变参数是可选的。

在这种情况下,printf用作strcpy,但解析%specifiers的fmt字符串。

我会写sprintf(toStr,"%s",fromStr);所以它不必解析那个长字符串。

1

第二个参数应该包含一个const char[]

const说明符函数参数的保证了函数不改变该参数的值(考虑它可以改变它是哪种情况因为它们通过地址传递给函数)。它不要求在实际调用中使用const值。

您发布的代码不使用const字符串作为sprintf()的第二个参数,但从非const到const的转换是隐式的;那里没有必要担心。

接受标准的ANSI C格式说明

“接受” 并不意味着 “需要”。您指定的格式字符串不包含任何格式说明符。因此,该函数只有2个参数(没有值格式)被调用。无论如何,sprinf()会忽略第三个参数,许多现代编译器会发出警告。


更新:我不想开始辩论哪些编译器是现代化的,哪些不是。

碰巧我使用OSX 10.11默认的编译器,这是什么输出:

axiac: ~/test$ cc -v 
Apple LLVM version 7.0.2 (clang-700.1.81) 
Target: x86_64-apple-darwin15.3.0 
Thread model: posix 
axiac: ~/test$ cc -o 1 1.c 
1.c:8:25: warning: data argument not used by format string [-Wformat-extra-args] 
    sprintf(x, "abc\n", n); 
       ~~~~~~~^
+0

我添加了一个更新到我的答案。由于格式化,无法将其添加为注释。 – axiac

+0

我刚测试过'gcc版本4.6.3(Ubuntu/Linaro 4.6.3-1ubuntu5)'。它有一个标志'-Wformat',它表示*“检查对”printf“和”scanf“等的调用,以确保提供的参数的类型与指定的格式字符串相匹配,并且格式字符串中指定的转换合理。”*。也许你的编译器也执行这样的检查,但是它们并未默认启用,你需要在选项之后挖掘文档:-) – axiac