嵌入式开发——移植printf函数源码到裸机程序中

发布时间:2023年12月24日

1、printf函数的移植思路

  • printf函数可以分为纯软件层和硬件相关层
    • 纯软件层:
      • 负责printf函数的参数解析,包括字符串的格式化和匹配等,比如:%d、%p
      • 纯软件层是和硬件无关,所以移植printf函数时不需要修改纯软件层的
    • 硬件相关层:
      • 将字符发生出去的具体方式,比如:可以通过uart输出字符串,可以通过屏幕屏幕输出字符串
      • 在移植的平台中,你想把字符显示到哪里,就把底层发送字符的函数替换成相应的发送函数
  • printf函数的工作流程:
    • printf函数是可变参数,printf函数首先会进行字符串匹配,就是处理“%d、%p…”
    • 解析好字符串后,是以字符为单位进行发送的
    • 想要把打印显示在哪里,就把字符发送函数重定位到哪里
  • 总结:纯软件层不需要修改,只需要替换底层的字符发送函数,也就是根据硬件平台替换putc函数

2、移植printf函数的步骤

2.1、printf函数源码获取

  • 去linux内核源码、C标准库的源码中裁剪出printf函数源码——适合有经验的
  • 直接移植别人现成的printf函数源码,只需要根据硬件平台替换putc函数——适合新手
  • 注意:gcc标准库里已经实现printf函数,如果你要使用自己实现的printf函数,添加编译参数“-nostdlib、-nostdin”,不使用C标准库和头文件,防止冲突;或者向我的源码一样,不要使用printf这个名字,自己加一些前缀,解决冲突问题

2.2、printf.c

#include "printf.h"
#include "uart.h"

#define ASCII_LF 10
#define ASCII_0 48

#define va_start(v, l) __builtin_va_start((v), l)
#define va_end __builtin_va_end
#define va_arg __builtin_va_arg

#define DEC_BASE 		10
#define HEX_BASE		16
#define IS_UNSIGNED		1
#define NOT_UNSIGNED	0
#define PRINT_BUF_LEN	64
#define PAD_ZERO		2
#define PAD_PREFIX		4

typedef __builtin_va_list va_list;

void my_putc(const char c)
{
	if(c == '\n')
	{
		//发送单个字符的函数,需要根据硬件平台实现
		//uart_send(ASCII_LF);
	}
	else
	{
		//发送单个字符的函数,需要根据硬件平台实现
		//uart_send(c);
	}
}


void my_puts(const char *str)
{
	while(*str)
	{
		my_putc(*str);
		str++;
	}
}

static void my_printi(long long num, int base, int u, int width, int pad_flag, int letbase)
{
	char print_buf[PRINT_BUF_LEN];
	int neg = 0;
	char *str;
	unsigned long long val = num;
	unsigned long long t;
	int count = 0, pad = 0;

	if(u == NOT_UNSIGNED && base == DEC_BASE && num < 0)
	{
		neg = 1;
		val = num;
	}

	str = print_buf + PRINT_BUF_LEN - 1;
	*str = '\0';

	if(!val)
	{
		*--str = '0';
		count++;
	}
	else
	{
		while (val)
		{
			t = val % base;
			val = val / base;
			if(t >= 10)
			{
				t = t- 10 + letbase;
				*--str = t;
			}
			else
			{
				*--str = t + ASCII_0;
			}
			count++;
		}
	}

	count = width - count;
	if((count > 0) && (pad_flag & PAD_ZERO))
	{
		while(count--)
		{
			*--str = ASCII_0;
		}

		pad = 1;
	}

	if(pad_flag & PAD_PREFIX)
	{
		if((base == HEX_BASE) && (letbase == 'A'))
		{
			pad ? (*(str + 1) = 'X') : (*--str = 'X');
		}
		if((base == HEX_BASE) && (letbase == 'a'))
		{
			pad ? (*(str + 1) = 'x') : (*--str = 'x');
		}
		pad ? (*(str) = '0') : (*--str = '0');
	}

	if(neg)
	{
		if(width && (pad_flag & PAD_ZERO))
		{
			*--str = '-';
		}
		else
		{
			*--str = '-';
		}
	}

	while(*str)
	{
		my_putc(*str);
		str++;
	}
	
}

static void my_vprintf(const char * format, va_list args)
{
	int width = 0;
	int pad_flag = 0;
	for(; *format != 0; ++format)
	{
		if(*format == '%')
			{
				++format;
				width = 0;

				if(*format == '\0')
				{
					break;
				}

				if(*format == '%')
				{
					my_putc(*format);
				}

				if(*format == '#')
				{
					pad_flag |= PAD_PREFIX;
					format++;
				}

				if(*format == '0')
				{
					pad_flag |= PAD_ZERO;
					format++;
				}

				for(; *format >= '0' && *format <= '9'; ++format)
				{
					width = (width * 10) + *format - '0';
				}

				if(*format == 's')
				{
					char *str = va_arg(args, char *);
					int count = 0;
					while (*str)
					{
						my_putc(*str);
						count++;
						str++;
					}

					count = width - count;

					while(count > 0)
					{
						(pad_flag & PAD_ZERO) ? my_putc('0') : my_putc(' ');
						count--;
					}

					continue;
				}

				if(*format == 'c')
				{
					char ch = va_arg(args, int);
					my_putc(ch);
					continue;
				}

				if(*format == 'd' || *format == 'i')
				{
					int num = va_arg(args, int);
					my_printi(num, DEC_BASE, NOT_UNSIGNED, width, pad_flag, '0');
					continue;
				}

				if(*format == 'u')
				{
					int num = va_arg(args, unsigned int);
					my_printi(num, DEC_BASE, IS_UNSIGNED, width, pad_flag, '0');
					continue;
				}

				if(*format == 'x')
				{
					unsigned int num = va_arg(args, unsigned int);
					my_printi(num, HEX_BASE, IS_UNSIGNED, width, pad_flag, 'a');
					continue;
				}

				if(*format == 'X')
				{
					unsigned int num = va_arg(args, unsigned int);
					my_printi(num, HEX_BASE, IS_UNSIGNED, width, pad_flag, 'A');
					continue;
				}

				if(*format == 'p')
				{
					unsigned long num = va_arg(args, unsigned long);
					my_printi(num, HEX_BASE, IS_UNSIGNED, width, pad_flag, 'a');
					continue;
				}
				
				if(*format == 'P')
				{
					unsigned long num = va_arg(args, unsigned long);
					my_printi(num, HEX_BASE, IS_UNSIGNED, width, pad_flag, 'A');
					continue;
				}

				if(*format == 'l' && *(format + 1) == 'l')
				{
					unsigned long long num = va_arg(args, unsigned long long);
					if(*(format + 2) == 'u')
					{
						format += 2;
						my_printi(num, DEC_BASE, IS_UNSIGNED, width, pad_flag, '0');
					}
					else if(*(format + 2) == 'x')
					{
						format += 2;
						my_printi(num, HEX_BASE, IS_UNSIGNED, width, pad_flag, 'a');
					}
					else if(*(format + 2) == 'X')
					{
						format += 2;
						my_printi(num, HEX_BASE, IS_UNSIGNED, width, pad_flag, 'A');
					}
					else if(*(format + 2) == 'd')
					{
						format += 2;
						my_printi(num, DEC_BASE, NOT_UNSIGNED, width, pad_flag, '0');
					}
					else
					{
						format += 1;
						my_printi(num, DEC_BASE, NOT_UNSIGNED, width, pad_flag, '0');
					}

					continue;
				}
				else
				{
					unsigned long num = va_arg(args, unsigned long);
					if(*(format + 1) == 'u')
					{
						format += 1;
						my_printi(num, DEC_BASE, IS_UNSIGNED, width, pad_flag, '0');
					}
					else if(*(format + 1) == 'x')
					{
						format += 1;
						my_printi(num, HEX_BASE, IS_UNSIGNED, width, pad_flag, 'a');
					}
					else if(*(format + 1) == 'X')
					{
						format += 1;
						my_printi(num, HEX_BASE, IS_UNSIGNED, width, pad_flag, 'A');
					}
					else if(*(format + 1) == 'd')
					{
						format += 1;
						my_printi(num, DEC_BASE, NOT_UNSIGNED, width, pad_flag, '0');
					}
					else
					{
						my_printi(num, DEC_BASE, NOT_UNSIGNED, width, pad_flag, '0');
					}

					continue;
				}
			}
			else
			{
				my_putc(*format);
			}
	}
}

void my_printf(const char *format, ...)
{
	va_list args;
	va_start(args, format);
	my_vprintf(format, args);
	va_end(args);
}

2.3、printf.h

#ifndef __PRINTF_H__
#define __PRINTF_H__

void my_putc(const char c);
void my_puts(const char *buffer);

void my_printf(const char *fmt, ...);

#endif
文章来源:https://blog.csdn.net/weixin_42031299/article/details/135182992
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。