对下面这样的写法,大家可能不陌生:

sprintf(buf, “%s foo %d %d”, buf, var1, var2);

使用这个语句的最初目的,是用来实现格式化字符处理版本的’strcat’。
但是这么写是有问题的,看下面这个例子:

1 #include
2 #include
3
4 int main(void)
5 {
6 char buf[20];
7
8 memset(buf, ‘\0′, sizeof(buf));
9 strcpy(buf, “FOO”);
10 snprintf(buf, sizeof(buf), “%s%s”, buf, “BAR”);
11 printf(”%s\n”, buf);
12
13 memset(buf, ‘\0′, sizeof(buf));
14 strcpy(buf, “BAR”);
15 snprintf(buf, sizeof(buf), “%s%s”, “FOO”, buf);
16 printf(”%s\n”, buf);
17 }


大家可能期望其输出是:

FOOBAR
FOOBAR

但是,实际输出是:

BAR
FOOFOO

C标准draft文档n1362.pdf有这么一段(P308):
7.19.6.6 The sprintf function
Synopsis
1 #include
int sprintf(char * restrict s,
const char * restrict format, …);
Description
2 The sprintf function is equivalent to fprintf, except that the output is written into
an array (specified by the argument s) rather than to a stream. A null character is written
at the end of the characters written; it is not counted as part of the returned value. If
copying takes place between objects that overlap, the behavior is undefined.
Returns
3 The sprintf function returns the number of characters written in the array, not
counting the terminating null character, or a neg ative value if an encoding error occurred

即按照标准,sprintf的形参(parameter)是带restrict关键字的,即认为这些参数指向的东西不会在sprintf() 调用时同时被访问到,“sprintf(buf, “%s foo %d %d”, buf, var1, var2);”这样写法,实参(argument)buf在两处同时被访问到了,这样就造成 undefined behavior。
C库没有义务保证这样的代码的有效性。

避免办法:

1、使用strcat

2、增加一个变量

参考链接:

mass bug filing for undefined sn?printf use

Demystifying The Restrict Keyword