MIT OS 4. printf vsprint fprintf 格式化输出 @ Lab1

关于可变参数这里讲的很明白: http://www.cppblog.com/qiujian5628/archive/2012/02/01/41562.html

主要是C语言函数调用参数入栈顺序和va_list宏。

--> va_start(ap,所有参数中第一个参数)  ap指向参数列表,是一个地址。

--->va_arg(ap,type) ap改变,指向下一个参数,type是当前参数的类型

--->va_end 清除ap,就是ap指向NULL

另外还有一个扩展宏 va_cp。

Macro: void __va_copy (va_list dest, va_list src)

The __va_copy macro allows copying of objects of type va_list even if this is not an integral type. The argument pointer in dest is initialized to point to the same argument as the pointer in src.

This macro is a GNU extension but it will hopefully also be available in the next update of the ISO C standard.

If you want to use __va_copy you should always be prepared for the possibility that this macro will not be available. On architectures where a simple assignment is invalid, hopefully __va_copy will be available, so one should always write something like this:

 
{
  va_list ap, save;
  ...
#ifdef __va_copy
  __va_copy (save, ap);
#else
  save = ap;
#endif
  ...
}

关于va_list 不同编译器和体系结构可能会有不同(http://stackoverflow.com/questions/988290/populating-a-va-list),例如JOS里面定义采用编译器自带方案:

typedef __builtin_va_list va_list;

#define va_start(ap, last) __builtin_va_start(ap, last)

#define va_arg(ap, type) __builtin_va_arg(ap, type)

#define va_end(ap) __builtin_va_end(ap)

附上vsprintfmt.c内容:

void vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap)
{
        register const char *p;
        register int ch, err;
        unsigned long long num;
        int base, lflag, width, precision, altflag;
        char padc;

        while (1) {
                while ((ch = *(unsigned char *) fmt++) != '%') {
                        if (ch == '\0')
                                return;
                        putch(ch, putdat);
                }

                // Process a %-escape sequence
                padc = ' ';
                width = -1;
                precision = -1;
                lflag = 0;
                altflag = 0;
        reswitch:
                switch (ch = *(unsigned char *) fmt++) {

                // flag to pad on the right
                case '-':
                        padc = '-';
                        goto reswitch;

                // flag to pad with 0's instead of spaces
                case '0':
                        padc = '0';
                        goto reswitch;

                // width field
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                        for (precision = 0; ; ++fmt) {
                                precision = precision * 10 + ch - '0';
                                ch = *fmt;
                                if (ch < '0' || ch > '9')
                                        break;
                        }
                        goto process_precision;

                case '*':
                        precision = va_arg(ap, int);
                        goto process_precision;

                case '.':
                        if (width < 0)
                                width = 0;
                        goto reswitch;
				case '#':
                        altflag = 1;
                        goto reswitch;

                process_precision:
                        if (width < 0)
                                width = precision, precision = -1;
                        goto reswitch;

                // long flag (doubled for long long)
                case 'l':
                        lflag++;
                        goto reswitch;

                // character
                case 'c':
                        putch(va_arg(ap, int), putdat);
                        break;

                // error message
                case 'e':
                        err = va_arg(ap, int);
                        if (err < 0)
                                err = -err;
                        if (err >= MAXERROR || (p = error_string[err]) == NULL)
                                printfmt(putch, putdat, "error %d", err);
                        else
                                printfmt(putch, putdat, "%s", p);
                        break;

                // string
                case 's':
                        if ((p = va_arg(ap, char *)) == NULL)
                                p = "(null)";
                        if (width > 0 && padc != '-')
                                for (width -= strnlen(p, precision); width > 0; width--)
                                        putch(padc, putdat);
                        for (; (ch = *p++) != '\0' && (precision < 0 || --precision >= 0); width--)
                                if (altflag && (ch < ' ' || ch > '~'))
                                        putch('?', putdat);
                                else
                                        putch(ch, putdat);
                        for (; width > 0; width--)
                                putch(' ', putdat);
                        break;

                // (signed) decimal
                case 'd':
                        num = getint(&ap, lflag);
                        if ((long long) num < 0) {
                                putch('-', putdat);
                                num = -(long long) num;
                        }
                        base = 10;
                        goto number;

                // unsigned decimal
                case 'u':
                        num = getuint(&ap, lflag);
				        base = 10;
                        goto number;

                // (unsigned) octal
                case 'o':
                        // Replace this with your code.
                        putch('X', putdat);
                        putch('X', putdat);
                        putch('X', putdat);
                        break;

                // pointer
                case 'p':
                        putch('0', putdat);
                        putch('x', putdat);
                        num = (unsigned long long)
                                (uintptr_t) va_arg(ap, void *);
                        base = 16;
                        goto number;

                // (unsigned) hexadecimal
                case 'x':
                        num = getuint(&ap, lflag);
                        base = 16;
                number:
                        printnum(putch, putdat, num, base, width, padc);
                        break;

                // escaped '%' character
                case '%':
                        putch(ch, putdat);
                        break;

                // unrecognized escape sequence - just print it literally
                default:
                        putch('%', putdat);
                        for (fmt--; fmt[-1] != '%'; fmt--)
                                /* do nothing */;
                        break;
                }
        }
}
...

你可能感兴趣的:(MIT OS 4. printf vsprint fprintf 格式化输出 @ Lab1)