#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void minprintf(char *fmt, ...)
{
va_list ap;
char *p, *sval;
int ival;
double dval;
va_start(ap, fmt);
for (p = fmt; *p; p++) {
if (*p != '%') {
putchar(*p);
continue;
}
switch (*p++) {
case 'd':
ival = va_arg(ap, int);
printf("%d", ival);
break;
case 'f':
dval = va_arg(ap, double);
printf("%f", dval);
break;
case 's':
for (sval = va_arg(ap, char *); *sval; sval++)
putchar(*sval);
break;
default:
putchar(*p);
break;
}
}
va_end(ap);
}
int main(void)
{
minprintf("aaaaaaa%\0dddd");
return 0;
}
此代码来自C编程语言第二版 7.3可变长度参数列表
通常这个程序应该输出aaaaaa并停止但是它会输出aaaaaa dddd。 http://ideone.com/d3Akk
这真的是一个错误。
谢谢。
答案 0 :(得分:2)
如果前面有%
(在switch语句中),则忽略null终止符。这可能是也可能不是错误,但对于C函数来说肯定是非标准行为。但是,在您的情况下,它不会导致任何未定义的行为,并且几乎完成它所说的内容。
答案 1 :(得分:1)
使用像“aaa%”这样的格式字符串调用的函数将导致UB,打破了最小惊喜的原则。这是我书中的一个错误。
答案 2 :(得分:1)
你的问题是由于for
条件*p
你期望它停在第一个NULL,只有它没有?
所以你的问题是:“为什么它不会停在第一个NULL?”。答案:因为switch()
语句中的后增量。它首先评估开关块,然后递增指针。因此,在您的特定情况下,当函数看到百分号时,它会进入switch语句。由于NULL不是有效的格式说明符,因此交换机块默认为输出它。然后,由于后增量,指针向前移动一个字符,即d
。因此,*p
计算为d
,它不是0,因此for循环中的条件被定义为true。
minprintf("whoopsie%");
之类的操作,可能会出现边缘情况,其中for循环将尝试迭代超过字符串的结尾!