[技术问答] 实现 vsprintf

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


  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. }


daichaodai 发表于 2023-5-21 19:24 来自手机 | 显示全部楼层
使用格式化字符串可以实现printf函数功能。
ulystronglll 发表于 2023-6-6 13:36 | 显示全部楼层
如何使用vsprintf,vsnprintf等函数
janewood 发表于 2023-6-6 14:22 | 显示全部楼层
在传递可变参数列表时,需要按照格式化字符串中占位符的顺序传递相应的参数,否则输出结果可能会出现错误。
bestwell 发表于 2023-6-6 14:30 | 显示全部楼层
vsprintf()函数是单片机程序中常用的字符串处理函数之一,在调试和输出结果时具有很重要的作用。
hilahope 发表于 2023-6-6 14:45 | 显示全部楼层
在传递格式化字符串时,需要确保其符合标准的格式化占位符规范,如"%d"、"%f"等。
loutin 发表于 2023-6-6 14:57 | 显示全部楼层
单片机串口可以用printf发送数据吗?
olivem55arlowe 发表于 2023-6-6 15:03 | 显示全部楼层
编译vsprintf错误               
robincotton 发表于 2023-6-6 15:09 | 显示全部楼层
printf,sprintf,vsprintf之间的区别是什么呢
10299823 发表于 2023-6-6 15:21 | 显示全部楼层
如何用单片机写出类似printf的函数
plsbackup 发表于 2023-6-6 17:43 | 显示全部楼层
在调用vsprintf()函数之前,需要确保目标字符数组有足够的内存空间来存储写入的内容。否则,可能会导致数据溢出或者程序崩溃。
beacherblack 发表于 2023-6-6 17:53 | 显示全部楼层
该函数与sprintf()函数类似,但不同之处在于可以接受可变参数列表,即可以同时处理多个参数。
Bowclad 发表于 2023-6-8 17:57 | 显示全部楼层
和printf有什么区别吗?
saservice 发表于 2023-6-10 09:49 | 显示全部楼层
vsprintf()函数是C标准库中的一个字符串处理函数,用于将格式化的数据写入到字符数组中。
chenqianqian 发表于 2023-6-11 19:49 来自手机 | 显示全部楼层
VSprintf即格式化字符串函数,printf也是调用该函数。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

5736

帖子

4

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