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 プログラミング言語第 2 版 7.3 可変長引数リストからのものです。

通常、このプログラムは aaaaaaa を出力して停止するはずですが、代わりに aaaaaaa dddd を出力します。 http://ideone.com/d3Akk

それは本当にバグですか?

ありがとうございました。

4

3 に答える 3

2

%ヌルターミネータの前に(switchステートメントで)付いている場合は、ヌルターミネータを無視します。これはバグである場合とそうでない場合がありますが、C関数の非標準的な動作であることは確かです。ただし、あなたの場合、それは未定義の振る舞いを引き起こさず、それが言うことをほとんど行います。

于 2012-01-02T19:05:02.497 に答える
1

「aaa%」のようなフォーマット文字列を指定して呼び出された関数は、UB を引き起こし、最小驚きの原則を破ります。これは私の本のバグです。

于 2012-01-02T19:19:44.780 に答える
1

あなたの問題は、最初の NULL で停止すると予想されるfor条件のために、*pそうではないということですか?

あなたの質問は、「なぜ最初の NULL で止まらないのですか?」です。switch()回答:ステートメントのポスト インクリメントが原因です。最初に switch-block を評価し、次にポインターをインクリメントします。したがって、特定のケースで何が起こるかは、関数がパーセント記号を見ると、switch ステートメントにドロップすることです。NULL は有効な書式指定子ではないため、switch ブロックは既定でそれを出力します。次に、ポストインクリメントのために、ポインターが 1 文字前に移動しますd。したがって、*pd0 ではないため、for ループの条件は真であると定義されます。

編集:IMOにはバグがありますが、実際にはこれではありません:デフォルトの構成によって間違ったフォーマット指定子が黙って破棄されるという事実です。minprintf("whoopsie%");さらに、 for ループが文字列の末尾を超えて反復しようとするようなことをすると、エッジ ケースが発生する可能性があります。

于 2012-01-02T19:20:21.503 に答える