zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    高级(线性)素数筛
    Dijkstra(迪杰斯特拉)算法
    简单素数筛
    【解题报告】 POJ1958 奇怪的汉诺塔(Strange Tower of Hanoi)
    4 jQuery Chatting Plugins | jQuery UI Chatbox Plugin Examples Like Facebook, Gmail
    Web User Control Collection data is not storing
    How to turn on IE9 Compatibility View programmatically in Javascript
    从Javascrip 脚本中执行.exe 文件
    HtmlEditorExtender Ajax
    GRIDVIEW模板中查找控件的方式JAVASCRIPT
  • 原文地址:https://www.cnblogs.com/lilto/p/10920080.html
Copyright © 2011-2022 走看看