“C编程语言第2版”中的代码是否包含错误?

时间:2012-01-02 18:56:36

标签: c kernighan-and-ritchie

#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

这真的是一个错误。

谢谢。

3 个答案:

答案 0 :(得分:2)

如果前面有%(在switch语句中),则忽略null终止符。这可能是也可能不是错误,但对于C函数来说肯定是非标准行为。但是,在您的情况下,它不会导致任何未定义的行为,并且几乎完成它所说的内容。

答案 1 :(得分:1)

使用像“aaa%”这样的格式字符串调用的函数将导致UB,打破了最小惊喜的原则。这是我书中的一个错误。

答案 2 :(得分:1)

你的问题是由于for条件*p你期望它停在第一个NULL,只有它没有?

所以你的问题是:“为什么它不会停在第一个NULL?”。答案:因为switch()语句中的后增量。它首先评估开关块,然后递增指针。因此,在您的特定情况下,当函数看到百分号时,它会进入switch语句。由于NULL不是有效的格式说明符,因此交换机块默认为输出它。然后,由于后增量,指针向前移动一个字符,即d。因此,*p计算为d,它不是0,因此for循环中的条件被定义为true。

编辑:IMO中存在一个错误,但实际上并不是这个错误:默认构造默认地丢弃了错误的格式说明符。此外,如果您执行minprintf("whoopsie%");之类的操作,可能会出现边缘情况,其中for循环将尝试迭代超过字符串的结尾!