printf的封装与实现

Posted lilto

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了printf的封装与实现相关的知识,希望对你有一定的参考价值。

1 UART通信协议

1.1 UART通信的物理连接

技术图片

????图1 UART的物理连接

?

1.2 逻辑电平

用电平表示逻辑1和逻辑0,逻辑1和逻辑0用来组织计算机层面的数据。

?

1.3 电平标准

根据通讯使用的电平标准不同,串口通讯可分为 TTL标准及 RS-232 标准。

?

1.4 协议解析

通讯双方需要约定波特率,并约定一致的数据包格式才能保证正常收发数据。

1.4.1 波特率(bps)

单位时间内,发送数据的位数。

?

1.4.2 数据格式

串口通信一般以起始位作为一帧数据传输的开始,以结束位表示一帧数据传输的结束。每一帧数据一般由起始位、数据位、停止位、校验位组成。

起始位:由1个逻辑0的数据位表示;

停止位:由 0.5、1、1.5或 2个逻辑 1的数据位表示;

校验位(奇校验/偶校验):当为奇校验时,数据位和校验位中,逻辑1的数据位的个数为奇数个;当为偶校验时,数据位和校验位中,逻辑1的数据位的个数为偶数个。

技术图片

图2 115200,8n1; send 0b01000001

?

如图2所示,115200bps,则1/115200spb,即每传输一位需要1/115200秒,数据在(1/115200)/2处采样。

?

2 printf的实现

2.1 标准库中的printf

函数原型:

int printf(const char *format, ...)

返回值:

成功返回实际输出字符数,失败返回-1;

传入参数说明:

format:????固定参数

...:????????可变参数;参数的个数不确定,类型不确定;

?

2.2 可变参数的实现原理

调用子函数,函数的参数最终会以被压入栈中,被函数使用;通过格式控制符,实现对栈中传入参数的读取和使用。

在标准库中的实现:

typedef char* va_list;

#define _INTSIZEOF(n) ????????((sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1))????????//保证4字节对齐

#define va_start(ap, v) ????(ap = (va_list)&v + _INTSIZEOF(v)) ????????????????//获取第一个变参在栈中的地址

#define va_arg(ap, t) ????????(*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) ????//获取ap所指向的数据,并把ap偏移至下一个变参的地址

#define va_end(ap) ????(ap = (va_list)0)????????????????????????????//使ap指向空,避免野指针

技术图片

技术图片技术图片技术图片技术图片

技术图片技术图片技术图片技术图片技术图片

技术图片技术图片技术图片技术图片

技术图片技术图片技术图片????

技术图片

?

?

?

printf(format, arg1, arg2, arg3);参数在栈中的存放

?

2.3.1 对_INTSIZEOF(n)分析

栈指针总是4字节对齐的,因此使用_INTSIZEOF(n),使变量的大小是4的倍数(实际变量在栈中占据的空间)。

#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1)),对这个宏定义有一个形象的比喻:

比方说有一个箱子可以装4个瓶子,

如果我有8个瓶子 ,那么我需要2个箱子;

如果我有10个瓶子呢,我不能说我需要10除4,需要2.5个箱子吧,实际上我需要3个箱子;

那怎么求我实际需要的箱子数呢?

用一个容易理解的公式来求上述问题:

设我的瓶子数为B,我需要的箱子数为C,一个箱子最多可以装A个瓶子。

公式:C =(B+A-1)/ A (舍去余数)

技术图片技术图片技术图片技术图片因此,((sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1))相当于C * A。

?

?

2.3.2 对va_arg(ap, t)分析

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

这个宏定义实现了两个功能:

a、ap += _INTSIZEOF(t) —— 求下一个参数的指针

b、(*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) —— 取当前参数值,这个宏定义将返回的就是当前参数值

?

附录:源代码

uart.c —— 波特率:115200

技术图片

?

debug_printf.c

技术图片

?

?

以上是关于printf的封装与实现的主要内容,如果未能解决你的问题,请参考以下文章

类与封装形态

第五章---面向对象---1.封装之如何实现属性的隐藏/2.封装的意义/3.封装与扩展性/4.property的使用

C++类封装-公用接口与私有实现的分离

实现AOP功能的封装与配置的小框架

Objective-C的封装继承与多态

Python编程基础19:封装继承与多态