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

来源:互联网 发布:炫浪网络社区下载 编辑:程序博客网 时间:2024/06/03 20:53

关于可变参数这里讲的很明白: 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;                }        }}
...

原创粉丝点击