[技术问答] 实现printf

[复制链接]
1531|10
 楼主| minzisc 发表于 2023-5-21 15:56 | 显示全部楼层 |阅读模式


  1. #define va_start(ap, v) ap = (va_list)&v  // 把ap指向第一个固定参数v
  2. #define va_arg(ap, t) *((t*)(ap += 4))          // ap指向下一个参数并返回其值
  3. #define va_end(ap) ap = NULL                  // 清除ap

  4. /* 将整型转换成字符(integer to ascii) */
  5. static void itoa(uint32_t value, char** buf_ptr_addr, uint8_t base) {
  6.    uint32_t m = value % base;            // 求模,最先掉下来的是最低位   
  7.    uint32_t i = value / base;            // 取整
  8.    if (i) {                            // 如果倍数不为0则递归调用。
  9.       itoa(i, buf_ptr_addr, base);
  10.    }
  11.    if (m < 10) {      // 如果余数是0~9
  12.       *((*buf_ptr_addr)++) = m + '0';          // 将数字0~9转换为字符'0'~'9'
  13.    } else {              // 否则余数是A~F
  14.       *((*buf_ptr_addr)++) = m - 10 + 'A'; // 将数字A~F转换为字符'A'~'F'
  15.    }
  16. }

  17. /* 将参数ap按照格式format输出到字符串str,并返回替换后str长度 */
  18. uint32_t vsprintf(char* str, const char* format, va_list ap) {
  19.    char* buf_ptr = str;
  20.    const char* index_ptr = format;
  21.    char index_char = *index_ptr;
  22.    int32_t arg_int;
  23.    char* arg_str;
  24.    while(index_char) {
  25.       if (index_char != '%') {
  26.          *(buf_ptr++) = index_char;
  27.          index_char = *(++index_ptr);
  28.          continue;
  29.       }
  30.       index_char = *(++index_ptr);         // 得到%后面的字符
  31.       switch(index_char) {
  32.          case 's':
  33.             arg_str = va_arg(ap, char*);
  34.             strcpy(buf_ptr, arg_str);
  35.             buf_ptr += strlen(arg_str);
  36.             index_char = *(++index_ptr);
  37.             break;

  38.          case 'c':
  39.             *(buf_ptr++) = va_arg(ap, char);
  40.             index_char = *(++index_ptr);
  41.             break;

  42.          case 'd':
  43.             arg_int = va_arg(ap, int);
  44.       /* 若是负数, 将其转为正数后,再正数前面输出个负号'-'. */
  45.             if (arg_int < 0) {
  46.                arg_int = 0 - arg_int;
  47.                *buf_ptr++ = '-';
  48.             }
  49.             itoa(arg_int, &buf_ptr, 10);
  50.             index_char = *(++index_ptr);
  51.             break;

  52.          case 'x':
  53.             arg_int = va_arg(ap, int);
  54.             itoa(arg_int, &buf_ptr, 16);
  55.             index_char = *(++index_ptr); // 跳过格式字符并更新index_char
  56.             break;
  57.       }
  58.    }
  59.    return strlen(str);
  60. }

  61. /* 格式化输出字符串format */
  62. uint32_t printf(const char* format, ...) {
  63.    va_list args;
  64.    va_start(args, format);               // 使args指向format
  65.    char buf[1024] = {0};               // 用于存储拼接后的字符串
  66.    vsprintf(buf, format, args);
  67.    va_end(args);
  68.    return write(buf);
  69. }


单片小菜 发表于 2023-5-22 10:21 | 显示全部楼层
这个代码,写的漂亮
yorkbarney 发表于 2023-6-10 09:40 | 显示全部楼层
如何写出多串口共用printf函数语句
houjiakai 发表于 2023-6-10 09:54 | 显示全部楼层
用printf打印usart串口数据
lzmm 发表于 2023-6-10 10:02 | 显示全部楼层
重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口
phoenixwhite 发表于 2023-6-10 10:38 | 显示全部楼层
习惯使用printf这一函数进行数据输出和调试
sdlls 发表于 2023-6-10 10:43 | 显示全部楼层
使用微库,因为使用微库的话,不会使用半主机模式
pmp 发表于 2023-6-10 12:13 | 显示全部楼层
使用jlink ,代替串口printf输出
chenci2013 发表于 2023-6-10 12:38 | 显示全部楼层
如果你用的是arm芯片的单片机,重定向函数
benjaminka 发表于 2023-6-10 13:08 | 显示全部楼层
在使用printf之前添加重定向代码  
robertesth 发表于 2023-6-10 13:23 | 显示全部楼层
关闭半主机模式,并重定向printf #pragmaimport(__use_no_semihosting)//不使用半主机模式
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

5740

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部