码迷,mamicode.com
首页 > 其他好文 > 详细

printf的封装与实现

时间:2019-05-24 21:01:05      阅读:384      评论:0      收藏:0      [点我收藏+]

标签:start   返回值   采样   怎么   可变参数   串口通信   nts   使用   数据传输   

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的封装与实现

标签:start   返回值   采样   怎么   可变参数   串口通信   nts   使用   数据传输   

原文地址:https://www.cnblogs.com/lilto/p/10920080.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!