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