自己实现printf函数

在嵌入式开发中,常常会通过串口打印一些信息到PC终端,这就需要实现自己的printf函数。

  • 我们先通过man 3 printf来看一下printf函数的声明:
    int printf(const char *format, ...);
    format:固定参数
    … :可变参数(变参)

下面解析printf函数的使用:

这里写图片描述

x86平台VC6.0编译器中,stdarg.h头文件内变参宏定义如下,本次实现也printf函数也采用此定义:

变参宏根据堆栈生长方向和参数入栈特点,从最靠近第一个可变参数的固定参数开始,依次获取每个可变参数的地址。

typedef char * va_list;

#define _INTSIZEOF(n)       ( (sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1) )

#define va_start(ap,v)        ( ap = (va_list)&v + _INTSIZEOF(v) )

#define va_arg(ap, type)    ( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) )

#define va_end(ap)             ( ap = (va_list)0 )

各宏的含义如下:
_INTSIZEOF宏考虑到某些系统需要内存地址对齐。从宏名看应按照sizeof(int)即堆栈粒度对齐,即参数在内存中的地址均为sizeof(int)=4的倍数。例如,若在1≤sizeof(n)≤4,则_INTSIZEOF(n)=4;若5≤sizeof(n)≤8,则_INTSIZEOF(n)=8。
        为便于理解,简化该宏为:


#define _INTSIZEOF(n)  ((sizeof(n) + x) & ~(x))

x = sizeof(int) - 1 = 3 = 0b’0000 0000 0000 0011

~x = 0b’1111 1111 1111 1100

一个数与(~x)相与的结果是sizeof(int)的倍数,即_INTSIZEOF(n)将n圆整为sizeof(int)的倍数。

② va_start宏根据(va_list)&v得到第一个可变参数前的一个固定参数在堆栈中的内存地址,加上_INTSIZEOF(v)即v所占内存大小后,使ap指向固定参数后下个参数(第一个可变参数地址)。
固定参数的地址用于va_start宏,因此不能声明为寄存器变量(地址无效)或作为数组类型(长度难定)。
③va_arg宏取得type类型的可变参数值。首先ap+=_INTSIZEOF(type),即ap跳过当前可变参数而指向下个变参的地址;然后ap-_INTSIZEOF(type)得到当前变参的内存地址,类型转换后返回当前变参值。
va_arg宏的等效实现如下:

#define va_arg(ap,t)    (ap = ap + _INTSIZEOF(t), *(t *)(ap - _INTSIZEOF(t)))

④va_end宏使ap指针指向空,防止野指针


代码下载地址:https://gitee.com/zgdy/0_printf

my_printf.c函数的实现在注释中已经很清晰了。


一、在PC端来测试:

这里写图片描述
①:pc机中有操作系统所以测试时,my_printf.h中使用stdio.h中的putchar函数


#ifndef _MY_PRINTF_H
#define _MY_PRINTF_H

//#include "uart.h"
#include "stdio.h"
#define  __out_putchar  putchar


#define  MAX_NUMBER_BYTES  64

extern int my_printf_test(void);
int printf(const char *fmt, ...);

#endif /* _MY_PRINTF_H */

② main.c:

#include "my_printf.h"

int main(int argc,char **argv)
{
    printf("CZG~\n");
    my_printf_test();
    return 0;

}

结果:
这里写图片描述

二、在JZ2440上面来测试:

这里写图片描述

关于为什么要加lib1funcs.S文件说明:
http://blog.csdn.net/czg13548930186/article/details/78797744

①由于ARM裸机中没有操作系统环境,所以要自己实现putchar函数(并在uart.h中声明):
这里写图片描述
② 将lib1funcs.S和my_printf.c放在Makefile中一同编译进去:
这里写图片描述
结果:
这里写图片描述

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页