在使用一块stm32开发板时,取消勾选microlib
后,使用标准c 库,发现串口重定向失效,串口不再输出printf
字符串, 感觉很奇怪,这边理清下问题的原因:
microlib
是经过优化过的c
lib 库,通过microlib进行重定向的方法很简单:
#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
HAL_UART_Transmit(&UartHandle, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
至于为什么可以被重定向,这边找到了fputc
的源码:
int
fputc (int c, FILE *fp)
{
int result;
CHECK_FILE (fp, EOF);
if (!_IO_need_lock (fp))
result = _IO_putc_unlocked (c, fp);
_IO_release_lock (fp);
return result;
}
#ifndef _IO_MTSAFE_IO
#undef fputc_unlocked
weak_alias (fputc, fputc_unlocked)
#endif
其中定义了弱类型,编译器会用用户最新定义的函数覆盖掉此函数,具体可以参考3 文档。
但是如果使用ARM libc
, 根据arm 官网给出的解释:
ARM provides a number of runtime C and C++ libraries, including the ARM C libraries, the Rogue Wave Standard C++ Library, and ARM C libraries.
The following runtime C and C++ libraries are provided:
The ARM C libraries
The ARM C libraries provide standard C functions, and helper functions used by the C and C++ libraries. The C libraries also provide target-dependent functions that implement the standard C library functions such as printf() in a semihosted environment. The C libraries are structured so that you can redefine target-dependent functions in your own code to remove semihosting dependencies.
The ARM libraries comply with:
The C Library ABI for the ARM Architecture (CLIBABI).
The C++ ABI for the ARM Architecture (CPPABI).
只需要在开头加上以下声明:
#pragma import(__use_no_semihosting)
void _sys_exit(int x)
{
x = x;
}
FILE __stdout;
struct __FILE
{
int handle;
};
关于semihost
模式,找到一篇文章(2), 其中解释如下:
The way it is actually implemented by the tools depends upon which target CPU you are running on. With Cortex-M based MCUs, the bottom level of the C library contains a special BKPT instruction. The execution of this is trapped by the debug tools which determine what operation is being requested - in the case of a printf, for example, this will effectively be a “write character to stdout”. The debug tools will then read the character from the memory of the target board - and display it in the console window within the IDE.
简单说,就是arm 提供了一种通过debug 探针传递目标信息到host 的方式,即在开发环境中与目标平台交换信息,对于printf
来说,就是获取字符串,这种模式默认情况是开启的,如果需要重定向,需要显示声明不启用这种模式,告知编译器。
最后,关于semohost
的使用:
Important notes about using semihosting
When you have linked with the semihosting library, your application will no longer work standalone - it will only work when connected to the debugger.
Semihosting operations cause the CPU to drop into “debug state”, which means that for the duration of the data transfer between the target and the host PC no code (including interrupts) will get executed on the target. Thus if you application uses interrupts, then it is normally advisable to avoid the use of semihosting whilst interrupts are active. If you still need to use printf, then you can retarget the bottom level of the C library to use an alternative communication channel, such as a UART.
Reference: