| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1182 人关注过本帖
标题:[分享]简谈C语言的可变参数表
只看楼主 加入收藏
栖柏
Rank: 2
等 级:论坛游民
威 望:3
帖 子:1103
专家分:17
注 册:2007-8-23
收藏
 问题点数:0 回复次数:3 
[分享]简谈C语言的可变参数表

简谈C语言的可变参数表
栖柏

最近翻开了StandardC99看到了关于可变参数表的内容,附件中有些资料可以参考,有什么重点请高手指教,本人也在学习中,在这里简谈C语言的可变参数表,要知道其更多知识请查阅相关资料,我只写下我对其的一点点认识和感受,有什么不对的地方请指出,仅供交流学习。

Preface:
我们的C语言入门教材都喜欢用printf(“Hello World!”);
这可以说是我们的第一个函数,其原型为int printf(const char *format, arg_list);
arg_list 要显示的参数变量列表,多个变量以逗号分隔
format 参数输出的格式,定义格式为:
%[flags][width][.perc] [F|N|h|l]type(具体格式见附件)
请注意它可以接受不定量(0-n)的参数。
因此我们可以用可变参数表根据需要确定参数数目。

CH1:
在ANSI中采用头文件stdarg.h编写的程序来实现可变参数表的功能,兼容性好,还有一种和以前程序兼容的varargs.h方式。在附件中有stdarg.h的头文件内容,从中可以看出从中引入了_Cdecl调用约定。在附件中可以看到相关的在VC和TC中的头文件,其中在VC中有这样的宏定义:(注variable-argument(va)可变参数)
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
注:_INTSIZEOF(n)得到最后一个参数的实际内存大小;&v是最后一个固定参数的起始地址;( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )用户所需的植通过其类型进行参数地址的强行转换,指针指向参数实际大小的末尾得到下一个参数首地址。
其函数形式为:
void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */
type va_arg ( va_list arg_ptr, type );
void va_end ( va_list arg_ptr );
注:va_list是一个char型指针,也有void *型;arg_ptr是指向va表的指针,prev_param是指va表的前一个参数;type是指类型。看有资料说sizeof(char)为1;其他类型sizeof(type)都大于1。
其中va_start和va_end是相对应的,va_start获取va表的首地址,将那固定参数地址加上可变参数队其偏移量va表首地址ap,在TC的stdarg.h中可以看出va_end是为空,没有任何东西。Va_arg中arg_ptr指向当前参数,ap指向当前参数的地址并指针指向下一个参数。

CH2:
也许我们在编函数的时候很少编带可变参数的函数,我们都知道我们在编函数的是时候,要调用栈,也就是说参数是存储在连续的栈里面的,知其一指针的指向我们就可以对其进行访问了。对了在macro(宏)里面“…”指可变参数,表示0或多个。比如简单的printf函数:
#include <stdarg.h>
int printf(char* format, …)/*我们在定义函数时“…”不要省略*/
{
va_list ap;
va_start(ap, format);/*将可变长参数转换为va_list*/
int n = vprintf(format, ap);
va_end(ap);
return n;
}
由此我们可以对可变参数表使用方法略见一斑了。有时需用va_arg各一取出所要的参数。具体一些用法,请大家用搜索引擎搜索一下。注意va_arg用了加宽原则,也就是说char要用int,以此类之。

CH3:
从附件中的所给的文件可以看出stdarg.h所给的macro定义是不相同的,即与编译器有关,事实上也与硬件有关。大家用DEV-CPP的可以找一找它的stdarg.h看看。在C++可以用多态来实现va的功能,避免了一些栈的一些缺点,比如溢出,在使用时注意开辟足够大的空间。要说栈,参数是连续存储在里面的,在许多编译器中,如VC参数进栈是从右向左的,也就是为什么printf(“%d”,--i,i,i++);在不同编译器得到不同植的原因。栈在内存里是这样的:
□←SS (堆栈寄存器)栈基地址位置 地址低



□←SP (堆栈指针寄存器,或ESP)栈顶地址位置 地址高


其进栈操作是先进的在地址高的地方,然后SP指针16位减2,32位减4;不同的内存表达方式可能参数的地址不同。具体的我就不再赘述,请大家勤于查阅资料,如有不对或不妥的地方,欢迎指出。
对了上次在论坛里看到关于macro中的#define的替换序列中#和##的使用,在这里看两个例子,具体用法请查相关资料,强烈建议看StandardC99和The C Programming Language。
#define dprint(expr) printf(#expr “=%g\n”,expr)
如果使用dprint(x/y);调用该宏时,该宏被扩展为:
printf(“x/y” “=%g\n”,x/y);
等价于printf(“x\y=%g\n”,x\y);
关于##请看#define paste(front,back) front##back
如果paste(name,1)的结果将建立记号name1;
以上例子是 The C Programming Language中的。
就不离题了,时间原因,就不多说了,我的学习笔记而已,仅供参考。

相关附件如下:

fNvBL7nZ.rar (6.42 KB) [分享]简谈C语言的可变参数表


搜索更多相关主题的帖子: C语言 参数表 可变 STRONG arg 
2007-09-09 11:45
coachard
Rank: 3Rank: 3
等 级:新手上路
威 望:7
帖 子:1251
专家分:0
注 册:2007-8-12
收藏
得分:0 
自从那次起,就没再看你原创过。。。

你咋就换了这个头像~~~~时时不忘老毛的教导

偶学编程,也许本身就是一个错。。。
2007-09-09 11:46
栖柏
Rank: 2
等 级:论坛游民
威 望:3
帖 子:1103
专家分:17
注 册:2007-8-23
收藏
得分:0 
开学了,真忙啊,有空会常来了,把你们竞赛的先收藏了,感觉在蓬勃发展呀
下午还有三节课,不知百年兄最近在做什么,想念他啊,还要祝贺他当了版主
以后多多关照啊,呵呵。先把东西下了。呵呵

You have lots more to work on! Never give up!c language!
2007-09-09 11:49
栖柏
Rank: 2
等 级:论坛游民
威 望:3
帖 子:1103
专家分:17
注 册:2007-8-23
收藏
得分:0 
coachard 呵呵,贴个最近我读书笔记做分享的,壮大自己的积分啊,呵呵,交流第一
不忘毛主席的教导

[此贴子已经被作者于2007-9-9 11:59:38编辑过]


You have lots more to work on! Never give up!c language!
2007-09-09 11:51
快速回复:[分享]简谈C语言的可变参数表
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.027229 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved