天天看點

printf 從現象到本質

講真,要深入了解 printf,隻能自己看源碼。

更精彩内容,可以關注我的部落格:wenfh2020.com

從現象到本質

前些時間,朋友問了一個問題:

printf

%s

格式輸出,如果參數是其它類型的資料強制轉換為

char*

的,結果會怎麼樣?

我想最好的方法莫過于馬上動手測試一下,看看結果。如果再問:printf 是線程安全的嗎?… 問題很多,這些都隻是問題的表象,要從現象看本質。Linux 是開源的,何不看源碼了解程式工作原理呢?

從源碼上看

strnlen

是通過查找記憶體的 ‘\0’ 字元串結束符的。如果強制轉換的記憶體資料,沒有 ‘\0’ 結束符,那

strnlen

就會出現問題。

/* https://github.com/torvalds/linux/blob/master/arch/x86/boot/printf.c */

int printf(const char *fmt, ...) {
    char printf_buf[1024];
    va_list args;
    int printed;

    va_start(args, fmt);
    printed = vsprintf(printf_buf, fmt, args);
    va_end(args);

    puts(printf_buf);

    return printed;
}

int vsprintf(char *buf, const char *fmt, va_list args) {
    ...
    switch (*fmt) {
        ...
        case 's':
            s = va_arg(args, char *);
            len = strnlen(s, precision);

            if (!(flags & LEFT))
                while (len < field_width--)
                    *str++ = ' ';
            for (i = 0; i < len; ++i)
                *str++ = *s++;
            while (len < field_width--)
                *str++ = ' ';
            continue;
    }
    ...
}

/* https://github.com/torvalds/linux/blob/master/arch/x86/boot/string.c */

size_t strnlen(const char *s, size_t maxlen) {
    const char *es = s;
    while (*es && maxlen) {
        es++;
        maxlen--;
    }

    return (es - s);
}
           

總結

不隻

printf

的實作,很多基礎函數,都能從 linux 源碼中檢視。可以從 github 下載下傳一份源碼,友善檢視。下載下傳個 zip 檔案包吧,git 檔案有點太大了。

/* https://github.com/torvalds/linux/blob/master/lib/string.c */

char *strcpy(char *dest, const char *src) {
    char *tmp = dest;

    while ((*dest++ = *src++) != '\0')
        /* nothing */;
    return tmp;
}
           
  • 更精彩内容,請關注作者部落格:wenfh2020.com