【printf】搞清楚printf重定位
调用链(典型 newlib / arm-none-eabi 编译器)
printf(...)
-> vfprintf(...)
-> fwrite/fputc(...) // 将数据写到 stdout 的缓冲区
-> 当需要向设备输出(缓冲满或 flush)时
-> 底层调用系统写函数 _write / sys_write / _write_r
-> 你在 syscalls.c / retarget.c 中提供的实现被调用
-> 硬件驱动(UART transmit / tud_cdc_write 等)
重要:fputc() 只是写入 FILE 流,只有在 flush / buffer full / 行缓冲遇到 \n(交互终端),或显式调用 fflush() 时,才会触发 _write()
fputc、_write、_write_r 之间的关系与差异
-
fputc(int ch, FILE *f):标准库函数,用于写单个字符到FILE流(例如stdout)。它是 C 标准库的一部分。 -
_write(int fd, const void *buf, int len)(或int _write(int file, char *ptr, int len)):newlib / syscalls 要实现的函数,用于将fd(通常 0 stdin, 1 stdout, 2 stderr)上的数据写到底层设备。实现它就是重定向printf的核心方法。 -
_write_r(struct _reent *r, int fd, const void *buf, int len):newlib 的可重入版本(在使用 reentrant newlib 时)。如果你的 toolchain 使用 reentrant syscalls,需要实现_write_r而不是_write。 -
sys_write:有些工程用这个名字替代_write,再通过宏或链接把它和_write绑定。
为什么直接重写 fputc() 有时无效或不稳定
-
fputc()写的是FILE的缓冲区;如果库/运行时没有立刻 flush(例如你在行缓冲之外、或者 stdout 不是交互式终端),数据可能不会立刻通过_write()发出。 -
标准库内部实现很复杂:
printf/vfprintf可能用fwrite()绕过fputc()的逐字符路径(一次性写大块),所以单独覆盖fputc()不一定能拦截所有printf输出。 -
因此推荐直接实现
_write(),这是 newlib 设计用于替代操作系统 write 的入口,能统一所有 stdout/stderr 输出。

浙公网安备 33010602011771号