一、要点:
实现sprintf,printf的要点在于不定参数的接收与处理,即va_list的使用,另外使用va_list需要包含stdarg.h头函数,想了解详细用法可以自行查找。
另外就是涉及数据的处理与转换,常用的是整型转字符串,以及各种类型转各种格式的字符串。
二、自己实现的类型转换函数
cpp
//整形转字符串
void cc_int2str(char *str,int value)
{
char tmp_str[20] = {0};
int lidx = 0;
char flag = 0;
int tmp_val;
if(value<0){
flag = 1;
tmp_val = -value;
}else{
tmp_val = value;
}
while(1){
if(tmp_val==0){
break;
}else{
tmp_str[lidx++] = 0x30+tmp_val%10;
tmp_val = tmp_val/10;
}
}
if(flag){
tmp_str[lidx++] = '-';
}
while(lidx--){
*str++ = tmp_str[lidx];
}
*str = 0;
}
//整形转16进制字符串
void cc_int2hexstr(char *str,int value)
{
char tmp_str[20] = {0};
int lidx = 0;
char flag = 0;
int tmp_val;
if(value<0){
flag = 1;
tmp_val = -value;
}else{
tmp_val = value;
}
while(1){
if(tmp_val==0){
break;
}else{
if(tmp_val%16<10){
tmp_str[lidx++] = 0x30+tmp_val%16;
}else{
tmp_str[lidx++] = 0x40+(tmp_val%16-9);
}
tmp_val = tmp_val/16;
}
}
if(flag){
tmp_str[lidx++] = '-';
}
while(lidx--){
*str++ = tmp_str[lidx];
}
*str = 0;
}
//字符串拷贝函数
int cc_strncpy(char * des,char * src,uint16_t n)
{
if(src && des && n){
while(n-->0){
if(*src){
*des++ = *src++;
}else{
*des++ = *src++;
break;
}
}
return 0;
}else{
return -1;
}
}
//字符串拼接函数
int cc_strcat(char * des,char * src)
{
if(src && des){
while(*des){
des++;
}
while(*src){
*des++ = *src++;
}
*des++ = *src++;
return 0;
}else{
return -1;
}
}
//字符串拼接指定长度函数
int cc_strncat(char * des,char * src,uint16_t n)
{
if(src && des && n){
while(*src){
src++;
}
while(n-->0){
if(*src){
*des++ = *src++;
}else{
*des++ = *src++;
break;
}
}
return 0;
}else{
return -1;
}
}
三、实现sprintf函数
cpp
//记得包含 #include "stdarg.h"
void cc_sprintf(char * des,const char *format, ...) {
char tmp_str[20] = {0};
va_list args;
va_start(args, format);
*des = 0;
while (*format) {
switch (*format) {
case '%':
++format;
switch (*format) {
case 'd': {
int val = va_arg(args, int);
cc_int2str(tmp_str,val);
cc_strcat(des,tmp_str);
break;
}
case 'x': {
int val = va_arg(args, int);
cc_int2hexstr(tmp_str,val);
cc_strcat(des,tmp_str);
break;
}
case 's': {
char *str = va_arg(args, char *);
cc_strcat(des,str);
break;
}
default:
cc_strcat(des,"%");
if (*format) {
tmp_str[0] = *format;
tmp_str[1] = 0;
cc_strcat(des,tmp_str);
}
break;
}
break;
default:
tmp_str[0] = *format;
tmp_str[1] = 0;
cc_strcat(des,tmp_str);
break;
}
++format;
}
va_end(args);
}
四、实现printf函数
cpp
//记得包含 #include "stdarg.h"
//代码主要针对单片机平台,其他平台请自行修改pchar函数
//串口初始化
void Debug_UartCfg(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_9);
gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_10);
rcu_periph_clock_enable(RCU_USART0);
usart_deinit(USART0);
usart_baudrate_set(USART0,115200);
usart_stop_bit_set(USART0,USART_STB_1BIT);
usart_word_length_set(USART0,USART_WL_8BIT);
usart_parity_config(USART0,USART_PM_NONE);
usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
}
int pchar(char c)
{
while(!usart_flag_get(USART0,USART_FLAG_TBE));
usart_data_transmit(USART0,c);
while(!usart_flag_get(USART0,USART_FLAG_TC));
return 0;
}
int putstr(char * c)
{
while(*c){
pchar(*c++);
}
return 0;
}
void cc_printf(const char *format, ...) {
char tmp_str[20] = {0};
va_list args;
va_start(args, format);
while (*format) {
switch (*format) {
case '%':
++format;
switch (*format) {
case 'd': {
int val = va_arg(args, int);
int2str(tmp_str,val);
putstr(tmp_str);
break;
}
case 'x': {
int val = va_arg(args, int);
cc_int2hexstr(tmp_str,val);
putstr(tmp_str);
break;
}
case 's': {
char *str = va_arg(args, char *);
putstr(str);
break;
}
default:
pchar('%');
if (*format) {
pchar(*format);
}
break;
}
break;
default:
pchar(*format);
break;
}
++format;
}
va_end(args);
}