资源描述:
《可变参数函数printf调用过程的分析 》由会员上传分享,免费在线阅读,更多相关内容在工程资料-天天文库。
1、可变参数函数printf调用过程的分析张春玲潍坊科技学院山东寿光262700【文章】printf是C中功能比较强大的一个可变参数函数,本文通过分析printf函数调用过程中的参数入栈,参数访问,参数出栈的实现,以帮助正确使用printf函数。【关键词】C;printf函数调用;可变参数函数1可变参数函数在程序设计中,可变参数函数是指函数拥有不定参数。C语言中常见的printf函数就是比较典型的可变参数函数。它的函数原型:intprintf(char*fmt,...);函数参数中,除了有一个参数fmt
2、固定以外,后面参数的个数和类型是可变的(...)。2栈栈就是一个具有先进后出属性的动态内存区域。栈的增长方向是向下增长,即由高地址向低地址方向。栈的这种先进后出特性有广泛运用。函数调用是间接使用栈的最好例子。3printf调用过程的分析printf函数的功能是按照用户指定的格式,将数据格式化然后向系统默认的输出设备输出若干个任意类型的数据。函数调用时,实现参数之间的传递,必须先将参数读取到堆栈中,然后再调用函数。C语言函数参数采用自右向左的入栈顺序,即函数的最后一个参数先入栈,第一个参数最后入栈;对
3、于printf函数,通过指针找到的第一个参数就是固定参数fmt。3.1printf函数参数的入栈C调用协议下,为了遵循“对齐“原则,对Intel80x86机器来说就是要求每个变量的地址都是sizeof(int)的倍数,因此参数入栈都是整数字节。那为什么要对齐?因为在对齐方式下,CPU的运行效率要快得多。同时在C语言中,调用一个不带原型声明的函数时,调用者会对每个参数执行“默认实际参数提升”。提升工作如下:1)float类型的实际参数将提升到double(分配8个字节)。2)char、short和相应
4、的signed、unsigned类型的实际参数提升到in(t4个字节),如果int不能存储原值,则提升到unsignedint。然后,调用者将提升后的参数传递给被调用者。因此printf的参数入栈时根据参数类型以及类型提升规则来分配相应大小的栈空间。printf()参数入栈过程如实例:floatf1;doublef2;intn1;longn2;charc1;…printf("%f,%f,%d,%ld,%c",f1,f2,n1,n2,c1);printf调用告诉计算机,要把参数f1,f2,n1,n2,
5、c1的值交给计算机,它把这些参数值依次入栈。入栈时根据参数定义时的类型以及提升规则而不是转换说明符,将参数自右向左入栈,入栈为c1(char提升为int)分4个字节,n2分4个字节,n1放了4个字节,f2放8个字节f1放8个字节(float提升为double),最后格式字符串入栈。3.2访问printf参数printf参数入栈后,调用函数,然后访问参数。对于可变参数函数,当传递的参数个数大于1时,是无法判断后面参数的类型,不知道类型就不知道后面参数在栈中占用多大空间,那也就无法通过移动指针读取栈中相
6、应大小的参数值,那函数也就无法正确使用参数值。那对于printf函数,它又如何正确输出各个实参的值?3.3printf通过格式字符串来读取后面参数对于编译器来说,printf函数的第一个固定参数就是一个普通字符串,如何通过这个字符串识别参数类型,在printf函数实现中,是通过循环判断字符串中的每一个字符,如果是普通字符,直接输出,与栈中参数值无关,对于‘%’后面的每个字符则借助于s);typeva_arg(va_listptr,type);voidva_end(va_listptr);函数里首先定
7、义一个va_list型的指__针变量ptr,这个变量是存储参数地址的指针。因为得到参数地址之后,再结合参数类型,才能得到参数值。va_start宏初始化ptr,将其指向第一个可变参数。很明显它先得到第一个固定参数内存地址,然后又加上这个固定参数prev_param的内存大小,就是第一个可变参数的内存地址了。va_arg宏有两个作用,首先返回ptr所指向的参数的值,然后自增指向下一个可变参数的地址。要得到参数值,必须借助type当前参数的类型(格式字符转换过来的类型),用来计算该参数的长度(指针移动的
8、步长),确定下一个参数的起始位置。它可以在函数中应用多次,直到得到函数的所有参数为止,但必须在宏va_start后面调用。在使用va_arg时,要注意type所用类型名应与传递到堆栈的参数字节数对应,以保证能对不同类型的可变参数进行正确地寻址。va_end宏在获取所有的参数后,设置指针ptr为NULL。printf("%f,%f,%d,%ld,%c",f1,f2,n1,n2,c1);参数访问过程如下:指针先指向第一格式字符串,首先遇到%f指定printf应读8个字节(