[牛人杂谈] 如何自己实现一个类似printf的函数

[复制链接]
920|1
 楼主| 598330983 发表于 2025-2-15 10:55 | 显示全部楼层 |阅读模式
在 ARM 单片机上实现一个简单的 printf 函数,可以通过自定义 putchar 或 fputc 函数来重定向输出。以下是一个简单的实现示例,假设你将输出重定向到串口(UART)。
1. 实现 putchar 函数
首先,实现一个简单的 putchar 函数,用于将字符发送到串口。

  1. #include "stm32f4xx_hal.h"  // 根据你的芯片型号包含对应的 HAL 库

  2. // 实现 putchar 函数
  3. int putchar(int ch) {
  4.     // 发送字符到串口
  5.     HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
  6.     return ch;
  7. }
2. 实现简单的 printf 函数
接下来,实现一个简单的 printf 函数,支持基本的格式(如 %d, %s, %c, %x 等)。

  1. #include <stdarg.h>  // 用于可变参数处理

  2. // 简单的 printf 函数实现
  3. void my_printf(const char *fmt, ...) {
  4.     va_list args;
  5.     va_start(args, fmt);  // 初始化可变参数列表

  6.     while (*fmt) {
  7.         if (*fmt == '%') {
  8.             fmt++;  // 跳过 '%'
  9.             switch (*fmt) {
  10.                 case 'd': {  // 处理整数
  11.                     int val = va_arg(args, int);
  12.                     if (val < 0) {
  13.                         putchar('-');
  14.                         val = -val;
  15.                     }
  16.                     char buffer[10];
  17.                     int i = 0;
  18.                     do {
  19.                         buffer[i++] = (val % 10) + '0';
  20.                         val /= 10;
  21.                     } while (val > 0);
  22.                     while (i > 0) {
  23.                         putchar(buffer[--i]);
  24.                     }
  25.                     break;
  26.                 }
  27.                 case 's': {  // 处理字符串
  28.                     char *str = va_arg(args, char *);
  29.                     while (*str) {
  30.                         putchar(*str++);
  31.                     }
  32.                     break;
  33.                 }
  34.                 case 'c': {  // 处理字符
  35.                     char ch = va_arg(args, int);
  36.                     putchar(ch);
  37.                     break;
  38.                 }
  39.                 case 'x': {  // 处理十六进制
  40.                     unsigned int val = va_arg(args, unsigned int);
  41.                     char buffer[8];
  42.                     int i = 0;
  43.                     do {
  44.                         int digit = val % 16;
  45.                         buffer[i++] = (digit < 10) ? (digit + '0') : (digit - 10 + 'A');
  46.                         val /= 16;
  47.                     } while (val > 0);
  48.                     while (i < 8) {
  49.                         buffer[i++] = '0';  // 补齐 8 位
  50.                     }
  51.                     while (i > 0) {
  52.                         putchar(buffer[--i]);
  53.                     }
  54.                     break;
  55.                 }
  56.                 default:
  57.                     putchar(*fmt);  // 未知格式,直接输出
  58.                     break;
  59.             }
  60.         } else {
  61.             putchar(*fmt);  // 普通字符,直接输出
  62.         }
  63.         fmt++;  // 移动到下一个字符
  64.     }

  65.     va_end(args);  // 结束可变参数处理
  66. }
3. 使用示例
在你的主程序中,可以像标准 printf 一样使用 my_printf 函数。

  1. int main(void) {
  2.     // 初始化 HAL 库和串口
  3.     HAL_Init();
  4.     SystemClock_Config();
  5.     MX_USART2_UART_Init();

  6.     // 使用自定义的 printf 函数
  7.     my_printf("Hello, World!\n");
  8.     my_printf("Integer: %d\n", 1234);
  9.     my_printf("String: %s\n", "ARM Cortex-M");
  10.     my_printf("Character: %c\n", 'A');
  11.     my_printf("Hexadecimal: 0x%x\n", 0xABCD);

  12.     while (1) {
  13.         // 主循环
  14.     }
  15. }
4. 代码说明
putchar: 将字符发送到串口。

my_printf: 支持 %d(整数)、%s(字符串)、%c(字符)和 %x(十六进制)等基本格式。

可变参数处理: 使用 va_list、va_start、va_arg 和 va_end 处理可变参数。


gaoyang9992006 发表于 2025-2-16 17:30 | 显示全部楼层
用自己实现的可以解决内存。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

267

主题

5575

帖子

22

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