c/c++ / printf 实现
一、源碼實現
#include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <assert.h>void my_printf(const char *fmt, ...) {va_list ap;va_start(ap, fmt); /* 用最后一個具有參數的類型的參數去初始化ap */for (; *fmt; ++fmt){/* 如果不是控制字符 */if (*fmt != '%'){putchar(*fmt); /* 直接輸出 */continue;}/* 如果是控制字符,查看下一字符 */++fmt;if ('\0' == *fmt) /* 如果是結束符 */{assert(0); /* 這是一個錯誤 */break;}switch (*fmt){case '%': /* 連續2個'%'輸出1個'%' */putchar('%');break;case 'd': /* 按照int輸出 */{/* 下一個參數是int,取出 */int i = va_arg(ap, int);putchar(i);}break;case 'c': /* 按照字符輸出 */{/** 但是,下一個參數是char嗎*//* 可以這樣取出嗎? */char c = va_arg(ap, char);putchar(c);}break;case 's':{char *pc = va_arg(ap, char *);while(*pc)putchar(*pc++);}break;}}va_end(ap);return; }int main() {my_printf("%s %s %c%c%c%c%c!\n", "welcome", "to", 'C', 'h', 'i', 'n', 'a');return 0; }二、缺陷分析
代碼編譯時會提示警告:
test_printf.c:41:33: warning: ‘char’ is promoted to ‘int’ when passed through ‘...’char c = va_arg(ap, char);不處理,直接執行程序,發現程序崩潰了。
問題就在于這行代碼:
char c = va_arg(ap, char);這里面會涉及“默認參數提升”的情況。
C語言中什么時候會牽扯到默認參數提升呢?
在C語言中,調用一個不帶原型聲明的函數時:調用者會對每個參數執行“默認實際參數提升(default argument promotions)。同時,對可變長參數列表超出最后一個有類型聲明的形式參數之后的每一個實際參數,也將執行上述提升工作。
提升工作如下:
-
float 類型的實際參數將提升到 double 。
-
char、short 和相應的 signed、unsigned 類型的實際參數提升到 int 。
-
如果 int 不能存儲原值,則提升到 unsigned int 。
所以,調用 my_printf 函數時,傳入的參數絕對不會是如下類型:
-
char、signed?char、unsigned?char
-
short、unsigned short
-
signed short、short int、signed?short int、unsigned?short int
-
float
所以正確的方案是將代碼
char c = va_arg(ap, char);?改為
int c = va_arg(ap, int);即可。
?
參考:
https://blog.csdn.net/astrotycoon/article/details/8284501
https://blog.csdn.net/iynu17/article/details/51588199
?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的c/c++ / printf 实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OS / linux 内核 read 操
- 下一篇: C++中,有哪4种与类型转换相关的关键字