zoukankan      html  css  js  c++  java
  • Printf可变參数使用

    參考文档: http://bbs.csdn.net/topics/70288067

    Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请标明来源 

     

    本文的二个重点:

    1. 可变參数实际上通过首个參数的地址来获取其他參数的地址。由于是顺序存储传过来的

    1.      可变參数为了处理方便。全部的浮点型都是依照double型压栈。

    因此,像printf採用的可变參数,它直接使用%f显示double型。不须要管float型。

     

    关注printf的精度,须要先关注printf的实现,关于printf的实现,我们就要关注一下可变參数的实现:

    变參的一个例了:

    void testIntAndFloat(int type, ...)

    {

        va_list argptr;

        va_start(argptr, type);

        if (type == 0 )

        {

            int n = va_arg( argptr, int );

            printf( "%d ", n );

        }

        else if (type == 1)

        {

            double d = va_arg( argptr, double); // 必须使用double接收,后边会说明原因

            printf( "%f ", d);

        }

        else

        {}

    }

    測试:

    float f1 = 12345;

    testIntAndFloat(0, 123);

    testIntAndFloat(1, f1, f1);

    输出:

    123

    12345.0000

    查看变參相关的定义:

    typedef charva_list;

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

    #define _ADDRESSOF(v)   ( &reinterpret_cast<constchar &>(v))

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

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

    //_ADDRESSOF(v):获取v的地址,并转为char*

    //_INTSIZEOF(n):实现4字节对齐

    //va_start (ap,v): 获取參数v之后的地址

    //va_arg(av, t): ap地址向后移t类型size,并返回ap地址之前t类型变量的值

     

     

    看一个输出%d的样例:

    __int64 i = 123456;

    printf("%d,%d ",i, i);

    结果为: 123456, 0

    printf("%d,%d,%d,%d ",i, i);

    结果为: 123456,0,123456,0

    printf("%lld,%lld ",i, i);

    结果为: 123456, 123456

    从上面的内容能够看出来:

    %d时,每次读取的位数是4位,而int648位。所以假设使用%d的话,分两次读取完。

    (因为是little endian。先读低位,再读高位,先读到123456。再读到0)

     

     

    再看输%f的样例

    float f = 123456789123456789.0;

    double fd = f;

    double d = 123456789123456789.0;

    printf("%f\%f %f ",f,fd, d);

    结果为:

    1234567939550609400.0000

    1234567939550609400.0000

    1234567890123456800.0000

     

    能够看出:

    float实际是被转成double型存储显示的

    float的精底一般是6-7位。double15-16位,printf的时候,显示的位数是按double算的。)

     

    再看这个样例,执行时观察内存信息:

    (观察内存方式: VC->调试->窗体->内存)

    void testArgs(int type, ...)

    {

        va_list argptr;

        va_start(argptr, type);

        for (int i=0; i<8; i++)

        {

            int* pNumber = (int*)argptr;

            float* pFloat = (float*)argptr;

            va_arg(argptr, int);

            printf((" addrss:%d int value: %d  float value: %f"), pNumber, *pNumber, *pFloat);

        }

    }

    void TestFuncArgs(int n1 = 31, float f1=31.0, double d1=31.0, char c1=31, bool b1=31, short s1=31, __int64 n2=31, int n3=31)

    {

        printf(" f1=%f", f1);

        printf((" addrss of arg(int): %x, value: %d"), &n1, n1);

        printf((" addrss of arg(float): %x, value: %d|%d, float:%f"), &f1, f1, f1);

        printf((" addrss of arg(double): %x, value: %d|%d, float:%f"), &d1, d1, d1);

        printf((" addrss of arg(char): %x, value: %d"), &c1, c1);

        printf((" addrss of arg(bool): %x, value: %d"), &b1, b1);

        printf((" addrss of arg(short): %x, value: %d"), &s1, s1);

        printf((" addrss of arg(__int64): %x, value: %d"), &n2, n2);

        printf((" addrss of arg(int): %x, value: %d"), &n3, n3);

        testArgs(n1, f1, d1, c1, b1, s1, n2, n3);

    }

     

    当按函数定參參数形式传递TestFuncArgs:

    Int/char/bool/short占用4字节

    Float占用4字节

    Double点用8字节

    __int64占用8字节

    内存中连续显示

    1f 00 00 00 --int

    00 00 f8 41 --float

    00 00 00 00 00 00 3f 40 --double

    1f 00 00 00 --char

    01 00 00 00 --bool

    1f 00 00 00 --short

    1f 00 00 00 00 00 00 00 int64

    1f 00 00 00 00 00 -- int

     

    当採用不定參数传递testArgs:

    其他均不变,但float8字节存储,这个是须要很注意的一个事情。

    使用%d打印时,仅仅会取4字节,须要使用两个%d%d才干打印一个float

    内存中连续显示

    1f00 00 00 -- int

    00 00 00 00 00 00 3f 40 --float

    00 00 00 00 00 00 3f 40 --double

    1f 00 00 00 --char

    01 00 00 00 --bool

    1f 00 00 00 --short

    1f 00 00 00 00 00 00 00 int64

    1f 00 00 00--double 
     
    Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu 转载请标明来源
     
  • 相关阅读:
    git 学习笔记
    单选框和复选框的样式修改
    es6常用方法
    js混杂笔记
    Entity Framework 学习第一天
    sublime text2的插件熟悉
    近况
    thinkphp ,进行关联模型的时候出现的问题,版本是3.2
    上传图片的权限问题
    今天学习了下,如何破解wifi
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7209972.html
Copyright © 2011-2022 走看看