zoukankan      html  css  js  c++  java
  • printf的实现原理

    printf的声明
        int _cdecl printf(const char* format, …);
        _cdecl是C和C++程序的缺省调用方式

    _CDEDL调用约定:
        1.参数从右到左依次入栈
        2.调用者负责清理堆栈
        3.参数的数量类型不会导致编译阶段的错误


    对于x86而言,栈向下生长,函数参数从右向左入栈,因此从第一个固定参数(format)地址向前(向上)移动就可得到其他变参的地址。

    va_list相关宏(VC++中stdarg.h里x86平台的宏定义)

    typedef char *  va_list;
    //_INTSIZEOF(n)宏:将sizeof(n)按sizeof(int)对齐。
    #define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

    //取format参数之后的第一个变参地址,4字节对齐
    #define va_start(va_list  ap, format) ( ap = (va_list)&format+ _INTSIZEOF(format) )

    //对type类型数据,先取到其四字节对齐地址,再取其值
    #define va_arg(va_list  ap,type)  
                  ( *(type*)((ap += _INTSIZEOF(type)) -_INTSIZEOF(type)) )

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


    如何得到参数个数?
    其实printf并不知道参数个数,它只是逐个解析format字符串。对于特定类型%,使用va_arg去取相应参数的值,直到遍历字符串结束。类似于如下代码:
        #include <stdio.h>
        #include <stdarg.h>
        void myprintf(const char *format, ...)
        {
                    va_list ap;
                    char ch;
                    va_start(ap, format);
                    while(ch = *format++)
                    {
                            switch(c)
                            {
                                        case 'c':
                                            {
                                                    char ch1 = va_arg(ap, char);
                                                  putchar(ch1);
                                                   break;
                                            }
                                      


    如下调用会打印什么内容?
    printf("%x");


    ----------------

    背景知识:

    函数调用栈帧结构:



    比如Z调用A,Z的栈帧:
    1.自右向左(约定)压入参数
    2.Z中返回地址。即从A返回后Z中下一条指令地址
    3.调用者的EBP。由编译器插入指令实现:
    "pushl %ebp"
    "movl %esp, %ebp"//esp为栈指针
    因而形成一个链表。依此可得到调用者的栈顶位置(对于A的EBP,得到Z的EBP地址为0x000f)。
    4.局部变量。



    对于两个正整数 x, n 总存在整数 q, r 使得
    x = nq + r, 其中  0<= r <n                  //最小非负剩余
    q, r 是唯一确定的。q = [x/n], r = x - n[x/n]. 这个是带余除法的一个简单形式。在 c 语言中, q, r 容易计算出来: q = x/n, r = x % n.
    所谓把 x 按 n 对齐指的是:若 r=0, 取 qn, 若 r>0, 取 (q+1)n. 这也相当于把 x 表示为:
    x = nq + r', 其中 -n < r' <=0                //最大非正剩余
    nq 是我们所求。关键是如何用 c 语言计算它。由于我们能处理标准的带余除法,所以可以把这个式子转换成一个标准的带余除法,然后加以处理:
    x+n = qn + (n+r'),其中 0<n+r'<=n            //最大正剩余
    x+n-1 = qn + (n+r'-1), 其中 0<= n+r'-1 <n    //最小非负剩余
    所以 qn = [(x+n-1)/n]n. 用 c 语言计算就是:
    ((x+n-1)/n)*n
    若 n 是 2 的方幂, 比如 2^m,则除为右移 m 位,乘为左移 m 位。所以把 x+n-1 的最低 m 个二进制位清 0就可以了。得到:
    (x+n-1) & (~(n-1))

  • 相关阅读:
    JAVA实现接口监控报警系统
    批量插入数据、自定义分页器
    django与Ajax
    ORM优化查询、choices参数
    django之查询操作及开启事务
    django之ORM字段及参数
    数据库设计
    django之模型层
    django之模板层
    django之视图层
  • 原文地址:https://www.cnblogs.com/socrates-lzstu/p/5295426.html
Copyright © 2011-2022 走看看