这段代码来自《C 编程语言第二版》吗?包含错误?
#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 可变长度参数列表
通常该程序应该输出 aaaaaaa 并停止,但它却打印 aaaaaaa dddd。 http://ideone.com/d3Akk
这真的是一个错误吗?
谢谢。
#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;
}
This code is from the C programming language second edition
7.3 Variable-length Argument Lists
Normally this program should output aaaaaaa and stops but instead it prints aaaaaaa dddd.
http://ideone.com/d3Akk
Is that really a bug.
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题是,如果空终止符前面有
%
(在 switch 语句中),则您会忽略它。这可能是也可能不是错误,但肯定是 C 函数的非标准行为。但是,就您而言,它不会导致任何未定义的行为,并且几乎按照它所说的进行。The thing is you ignore the null terminator if it is preceded by
%
(in the switch statement). That may or may not be a bug, but is certainly nonstandard behavior for C functions. However, in your case, it doesn't cause any undefined behavior and pretty much does what it says.使用像“aaa%”这样的格式字符串调用的函数会导致UB,违反了最小意外原则。这是我书中的一个错误。
The function called with a format string like "aaa%" will cause UB, breaking the principle of least surprise. This is a bug in my book.
您的问题是,由于
for
条件*p
您希望它在第一个 NULL 处停止,但事实并非如此?所以你的问题是:“为什么它不在第一个 NULL 处停止?”。答案:因为
switch()
语句中的后置自增。它首先评估开关块,然后递增指针。因此,在您的特定情况下发生的情况是,当函数看到百分号时,它会放入 switch 语句中。由于 NULL 不是有效的格式说明符,因此 switch 块默认输出它。然后,由于后递增,指针向前移动一个字符,即d
。因此,*p
的计算结果为d
,它不为 0,因此 for 循环中的条件被定义为 true。编辑:那里有一个错误,IMO,但实际上不是这个:事实上,默认构造会默默地丢弃错误的格式说明符。此外,如果您执行类似
minprintf("whoopsie%");
的操作,则可能会出现边缘情况,其中 for 循环将尝试遍历字符串末尾!Your problem being that because of the
for
condition*p
you'd expect it to stop at the first NULL, only it doesn't?So your question, is: "why does it not stop at the first NULL?". Answer: because of the post-increment in the
switch()
statement. It evaluates the switch-block first, then increments the pointer. So what happens in your specific case is that when the function sees the percent sign it drops into the switch statement. Because NULL is not a valid format specifier, the switch block defaults to outputting it. Then, because of the post-increment the pointer is moved ahead one character, which is ad
. Therefore,*p
works out asd
, which is not 0, therefore the condition in the for loop is defined to be true.EDIT: There is a bug in there, IMO, but it is not actually this one: it is the fact that wrong format specifiers are silently discarded by the default construct. Additionally, there may be an edge case if you'd do something like
minprintf("whoopsie%");
where the for loop will attempt to iterate past the end of the string!