C语言中的格式化打印printf/sprintf以及嵌入式printf重定向进行DEBUG

一、printf描述

在C语言中,打印函数主要包括printf/sprintf/fprintf/snprintf等等,目的是将“给定的内容”按照“指定的格式”输出到“指定目标内”。通常要使用时,需要包括#inlcude 头文件。

用法为:void printf(const char *fmt, ...),其中“...”为可变参数列表,fmt为指定的输出格式,打印参数时用%来占位,根据百分号后边的具体内容来指定参数的格式。

常用格式如下:

%ld、%lu : d和u前面加l表示长整形;

%8d,%8u : d和u前面加一个常数N指定格式化后的字符串长度,实际长度小于N,以空格填充左边,实际长度大于N则忽略N;

%08d,%08u : 当实际长度小于N时,希望以0填充左边,则在N前加0; 

%p : 显示指针的值

%e: 指数形式的浮点数

  1. printf("%d", value); 打印有符号十进制数:
  2. printf("%i", value); 打印有符号十进制数:
  3. printf("%u", value); 打印无符号十进制数:
  4. printf("%o", value); 打印无符号八进制数:
  5. printf("%x", value); 小写形式打印十六进制数: eg>1 2 e fa
  6. printf("%.2x", value); 小写形式打印十六进制数,不足2位左侧补零:eg> 02 ef
  7. printf("%X", value); 大写形式打印十六进制数:
  8. printf("%f", value); 打印浮点数:
  9. printf("%c", value); 打印ASCII单个字符
  10. printf("%.3f", value); 打印浮点数并保留小数点后3位
  11. printf("%s", str); 原样打印字符串:
  12. printf("%Ns", str); 打印指定长度的字符串, 超长时不截断, 不足时右对齐,N 为指定长度的10进制数值
  13. printf("%-Ns", str); 打印指定长度的字符串, 超长时不截断, 不足时左对齐,N 为指定长度的10进制数值

printf函数源码如下:


void printf(const char *fmt, ...) 
{ 
    char printf_buf[1024]; //可以放在外部,也可以放在函数内部 
    va_list args; //定义一个指针 args
    va_start(args, fmt); //args指向fmt中的待转换参数(%)
    vsprintf(printf_buf, fmt, args); //调用vsprintf进行格式化打印
    va_end(args); //结束格式化打印
    puts(printf_buf); 输出
} 

其中主要是用到了va_list,va_start,va_end,vsprintf,可以从stdarg.h中找到相关定义,va_arg(ap, type)是将ap指向的变量感召type类型进行返回。

#ifdef __clang__
  typedef __builtin_va_list va_list;
  #define va_start(ap, param) __builtin_va_start(ap, param)
  #define va_end(ap)          __builtin_va_end(ap)
  #define va_arg(ap, type)    __builtin_va_arg(ap, type)
  #if __STDC_VERSION__ >= 199900L || __cplusplus >= 201103L || !defined(__STRICT_ANSI__)
  #define va_copy(dest, src)  __builtin_va_copy(dest, src)
  #endif
#else

在传参数时,参数的入栈顺序是从右向左,出栈时是从左向右,因此,当格式化字符串的百分号占位符与参数列表的个数不匹配时,将按照从右往左的顺序进行赋值。

二、重定向

根据前面的描述,可以对printf进行修改输出方式,例如,需要用串口作为debug,那么只需将printf格式化打印好的字符串送给串口进行输出即可。

void DEBUG_Printf(char *fmt, ...)
{		
    char buf[128];//不能太大,注意栈溢出,导致HardFalut
    va_list va_args;//声明
    va_start(va_args, fmt);//指针指向格式化字符
    vsnprintf((char *)buf, sizeof(buf), fmt, va_args);//调用stdarg.h中的vsnprintf转换
    va_end(va_args);//转换结束
    UART_SendString(USART2,buf);//将buf送到串口
}

三、设置编译开关

可以设置_DEBUG_开关来选择是否需要打印日志。

#define _DEBUG_ 1
#if _DEBUG_
#define MSG(...) DEBUG_Printf(__VA_ARGS__)
#else
#define MSG(...)
#endif

 

你可能感兴趣的:(嵌入式,printf,嵌入式重定向)