这段代码来自《C 编程语言第二版》吗?包含错误?

发布于 2024-12-24 17:40:04 字数 1057 浏览 0 评论 0原文

#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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

风吹过旳痕迹 2024-12-31 17:40:04

问题是,如果空终止符前面有 % (在 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.

可是我不能没有你 2024-12-31 17:40:04

使用像“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.

故事和酒 2024-12-31 17:40:04

您的问题是,由于 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 a d. Therefore, *p works out as d, 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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文