帮助理解可变参数的应用【转贴】
来源:互联网 发布:mac有必要flash吗 编辑:程序博客网 时间:2024/05/01 16:04
C语言中不用宏va_list,va_start,va_arg写处理变长参数的函数
http://blog.sina.com.cn 2006年09月07日10:54 随机过程 标签:
C语言中变长参数(va_list,va_start,va_arg)沉思录
一.引言:
C语言中关于变长参数的使用很简单,无非是如下的框架。是否可以不用宏而编写处理变长参数的函数呢?答案是肯定的,本文作了一些处浅探讨,不足之处望各位批评指正。
使用宏的程序框架:
#include <stdio.h>
#include <stdart.h> /* 或者#include <vararg.h> */
int print (char * fmt, ...)
{
va_list args;
...
va_start (args, fmt);
/* do something here */
va_end (args);
/* do something here too */
}
我看了一下有关va_list, va_start, va_end宏的定义,各编译器不大一样,我着重研究了一下gcc的以上三个宏,并在不用三个宏的情况下编写了测试程序。测试过程和大家分享。
gcc中va_list的定义
#define char* va_list /* gcc中va_list等同char* */
gcc中三个宏的定义如下(经过我加工整理后):
#define va_start(AP, LASTARG) ( /
AP = ((char *)& (LASTARG) + /
__va_rounded_size(LASTARG)))
#define va_arg(AP, TYPE) ( /
AP += __va_rounded_size(TYPE), /
*((TYPE *)(AP - __va_rounded_size(TYPE))))
#define va_end(AP) /* 没有定义,没有操作 */
有的编译器这样定义:
#define va_end(AP) ((void *)0) /* 有定义,是空操作 */
二.不用宏的处理变长参数实践:
本人在分析了上面的宏后,在Linux、 i386、 gcc、 gas平台的Think Pad R50e上不用上面的三个宏成功写了个测试C代码,并详细分析了该代码的汇编代码,先给出代码如下:
/*****************************************************
* File Name : mytest.c
* Copyright by : Superware
* Version : 0.01
*****************************************************/
#include <stdio.h> /* 我没包含 stdarg.h 或 vararg.h */
void print (char * fmt, ...)
{
char * arg; /* 变长参数的指针
{
char * arg; /* 变长参数的指针
相当于 va_list arg */
int i; /* 接受int参数 */
double d; /* 接受double参数 */
char c; /* 接受char 参数*/
char *s; /* 接受字符串 */
int i; /* 接受int参数 */
double d; /* 接受double参数 */
char c; /* 接受char 参数*/
char *s; /* 接受字符串 */
printf ("%s", fmt); /* 打印第一个参数 fmt串 */
arg = (char *)&fmt + 4; /* 相当于 va_start(arg, fmt)
这里的 +4 实际上是
sizeof(char *) 因为在IA32
中,所以我写了4 没有考虑移植,
为什么? 在下面解释,
注意这里加 4表示arg已经指向
第二个参数 */
/* 打印第二个参数 */
i = *(int *)arg; /* 接受第二个参数,
/* 打印第二个参数 */
i = *(int *)arg; /* 接受第二个参数,
为了直接了当,我硬性规定
print()函数的第二个
参数是整数,请看 */
main()函数中的print()
函数调用 */
printf ("%d", i); /* 打印地二个参数,是整数,
printf ("%d", i); /* 打印地二个参数,是整数,
所以用格式"%d" */
arg += sizeof(int); /* 指向下一个参数(第三个参数),
arg += sizeof(int); /* 指向下一个参数(第三个参数),
为什么是加sizeof(int),
分析汇编码你就明白了 */
/* 打印第三个参数 */
d = *(double *)arg; /* 以下的解释同地二个参数类似,
就不详细解释了 */
printf ("%f", d);
arg += sizeof(double);
printf ("%f", d);
arg += sizeof(double);
/* 打印第四个参数 */
c = *(char *)arg;
printf ("%c", c);
arg += sizeof (char *);
printf ("%c", c);
arg += sizeof (char *);
/* 打印第五个参数 */
c = *(char *)arg;
printf ("%c", c);
arg += sizeof (char *);
printf ("%c", c);
arg += sizeof (char *);
/* 打印第六个参数 */
s = *(char **)arg;
printf ("%s", s);
arg += sizeof (char *);
printf ("%s", s);
arg += sizeof (char *);
arg = (void *)0; /* 使arg指针为 (void)0,
实际上就上使无效,否则arg
依然指向第六个参数,危险。*/
/* 相当于 va_end(arg) */
}
int main (void)
{
print ("Hello/n", 3, 3.6, '/n', 'a', "World/n");
{
print ("Hello/n", 3, 3.6, '/n', 'a', "World/n");
return 0;
}
}
/* File mytest.c ends here *******************/
代码有点长,其实很简单,只是机械地对main()函数中的print()函数中的6个参数进行处理,依次打印上面的6个参数(注意,我没有用格式化符号,带格式话符号的处理函数我将在下面给出),去掉注释,在Linux AS4.2 gcc-3.4.4中编译,运行结果如下:
/************************
Hello
33.600000
aWorld
*************************/
Hello
33.600000
aWorld
*************************/
与预想的完全一致。说明print()函数对变长参数的理解是正确的。
- 帮助理解可变参数的应用【转贴】
- 可变参数的应用
- 可变参数的应用
- 可变参数的基本应用
- 可变参数的函数应用
- 浅淡可变参数的应用
- C语言可变参数设计的理解
- 关于c++可变参数的理解
- java可变参数概念的理解
- 关于Python可变参数的理解
- 可变参数va_list的理解和使用
- java中可变长度参数的应用
- 如何应用Java的可变参数
- 如何应用Java的可变参数
- 如何应用Java的可变参数
- java 可变参数的应用
- C/C++可变参数省略号"..."的应用
- 可变参数初步应用
- ASP.NET程序中常用代码汇总-3[转]
- 中资银行或踏上国际扩张之路
- 一个免费的WebService获取IP信息
- .net CheckBox 回传事件的教训
- Fat 文件系统(2)
- 帮助理解可变参数的应用【转贴】
- ·vc 中读取两个不同的excel表中的某个格中的数并比较二者大小?请各位指教
- 文章学习_基于HowNet 的词汇语义倾向计算
- SQL文的管理和解析(一)利用Spring的Resource管理SQL的XML配置文件
- 亚瑟王
- 卡巴斯基误杀XP导致某IT网站电脑大面积瘫痪
- 中国承诺进一步开放资本市场
- 巴别塔的倒掉:Facebook和Google之争的真相
- 圆桌骑士团