C语言可变参数及stdarg.h中的三个宏定义
来源:互联网 发布:java迷宫小游戏代码 编辑:程序博客网 时间:2024/05/16 12:44
我们知道va_start,va_arg,va_end是在stdarg.h中被定义成宏的,由于1)硬件平台的不同 2)编译器的不同,所以定义的宏也有所不同,下面以VC++中stdarg.h里x86平台的宏定义
typedef char * va_list;
#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)主要是为了某些需要内存的对齐的系统.
C语言的函数是从右向左压入堆栈的,下图是函数的参数在堆栈中的分布位置.
高地址 |-----------------------------|
|函数返回地址 |
|-----------------------------|
|....... |
|-----------------------------|
|第n个参数(第一个可变参数) |
|-----------------------------|<--va_start后ap指向
|第n-1个参数(最后一个固定参数)|
低地址 |-----------------------------|<-- &v
va_start的定义,ap是va_list类型,v是固定参数,定义为&v+_INTSIZEOF(v),而&v是固定参数在堆栈的地址,所以我们运行va_start(ap, v)以后,ap指向第一个可变参数在堆栈的地址,如上图
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
va_arg(ap,t)取得类型t的可变参数值,以t是int类为例。
j=*(int*)( ( ap += _INTSIZEOF(int) )-_INTSIZEOF(int) )首先ap+=sizeof(int),已经指向下一个参数的地址了.然后返回ap-sizeof(int)的int*指针,这正是第一个可变参数在堆栈里的地址(图2).然后用*取得这个地址的内容(参数值)赋给j.
最后要说的是va_end宏的意思,x86平台定义为ap=(char*)0;使ap不再指向堆栈,而是跟NULL一样.有些直接定义为((void*)0),这样编译器不会为va_end产生代码
举例
#include <stdio.h>
#include <stdarg.h>
/* calculate sum of a 0 terminated list */
void sum(char *msg, ...)
{
int total = 0;
va_list ap;
int arg;
va_start(ap, msg);
while ((arg = va_arg(ap,int)) != 0) {
total += arg;
}
printf(msg, total);
va_end(ap);
}
int main(void) {
sum("The total of 1+2+3+4 is %d/n", 1,2,3,4,0);
return 0;
}
C语言中有一种长度不确定的参数,形如:"…",它主要用在参数个数不确定的函数中,我们最容易想到的例子是printf函数。注意:在C++中有函数重载(overload)可以用来区别不同函数参数的调用,但它还是不能表示任意数量的函数参数。
问题:printf的实现
请问,如何自己实现printf函数,如何处理其中的可变参数问题? 答案与分析:
#include <stdio.h>
#include <stdarg.h>
int printf(char* format, …)
{
va_list ap;
va_start(ap, format);
int n = vprintf(format, ap);
va_end(ap);
return n;
}
函数名: vprintf
功 能: 送格式化输出到stdout中
用 法: int vprintf(char *format, va_list param); 其中param指向可变参数的首地址
程序例:
#include <stdio.h>
#include <stdarg.h>
int vpf(char *fmt, ...)
{
va_list argptr;
int cnt;
va_start(argptr, format);
cnt = vprintf(fmt, argptr);
va_end(argptr);
return(cnt);
}
int main(void)
{
int inumber = 30;
float fnumber = 90.0;
char *string = "abc";
vpf("%d %f %s/n",inumber,fnumber,string);
return 0;
}
- C语言可变参数及stdarg.h中的三个宏定义
- C语言可变参数及stdarg.h中的三个宏定义
- 可变参数(C语言):stdarg.h
- [C语言]利用stdarg.h来实现可变参数列表
- c可变参数和stdarg.h
- c语言—stdarg宏(函数可变参数实现)
- C 语言的可变参数类型 stdarg
- 可变参数处理,stdarg.h
- 可变参数列表<stdarg.h>
- CC++可变参数stdarg.h中的余数运用
- C可变长参数表问题---stdarg.h宏定义va_start,va_arg,va_end
- C语言可变参数在宏定义中的应用
- C语言可变参数在宏定义中的应用
- stdarg.h编写可变参数函数
- C语言可变参数宏定义方法
- C语言中的可变参数函数 三个点“…”
- C语言中的可变参数函数 三个点“…
- C语言中的可变参数函数 三个点“…”
- IE中实现图片的拖拽
- 恶意代码依赖
- C# 字符串 合并时 + 和 stringbulilder 的区别是什么?
- RMI原理及实现
- 用c#创建支持多语言的应用程序
- C语言可变参数及stdarg.h中的三个宏定义
- Fedora 7上安装VMware Tools
- 开关电源和线性电源的区别
- (轉)如何将图片变成零字节
- C#关于socket同步编程
- 3D表面纹理合成技术
- 分析源代码126邮箱菜单效果学习javascript
- SQL Server 2000 Service Pack 4文档
- 联想全球实行两大品牌战略:"Think和Idea"