社区
C语言
帖子详情
如何编写一个类似于printf(char* prompt,....)的函数?
olmouse
2006-11-15 01:23:05
我想写一个函数,如下
void myfunc(char *prompt,...)
{
//若干代码后......
printf(prompt,...);//将从myfunc参数表中的后面的各项参数传给printf
}
如何编写?
谢谢
...全文
354
7
打赏
收藏
如何编写一个类似于printf(char* prompt,....)的函数?
我想写一个函数,如下 void myfunc(char *prompt,...) { //若干代码后...... printf(prompt,...);//将从myfunc参数表中的后面的各项参数传给printf } 如何编写? 谢谢
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
7 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
goodluckyxl
2006-11-15
打赏
举报
回复
http://blog.csdn.net/laomai
里面有一篇讲了 不过网上也有相同的
不知道是不是抄的
jsjxyf
2006-11-15
打赏
举报
回复
《c语言常见问题集》网上有下的 能解决你的问题
jixingzhong
2006-11-15
打赏
举报
回复
C中的可变参数研究
一. 何谓可变参数
int printf( const char* format, ...);
这是使用过C语言的人所再熟悉不过的printf函数原型,它的参数中就有固定参数format和可变参数(用”…”表示). 而我们又可以用各种方式来调用printf,如:
printf("%d",value);
printf("%s",str);
printf("the number is %d ,string is:%s", value, str);
二.实现原理
C语言用宏来处理这些可变参数。这些宏看起来很复杂,其实原理挺简单,就是根据参数入栈的特点从最靠近第一个可变参数的固定参数开始,依次获取每个可变参数的地址。下面我们来分析这些宏。在VC中的stdarg.h头文件中,针对不同平台有不同的宏定义,我们选取X86平台下的宏定义:
typedef char *va_list;
/*把va_list被定义成char*,这是因为在我们目前所用的PC机上,字符指针类型可以用来存储内存单元地址。而在有的机器上va_list是被定义成void*的*/
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
/*_INTSIZEOF(n)宏是为了考虑那些内存地址需要对齐的系统,从宏的名字来应该是跟sizeof(int)对齐。一般的sizeof(int)=4,也就是参数在内存中的地址都为4的倍数。比如,如果sizeof(n)在1-4之间,那么_INTSIZEOF(n)=4;如果sizeof(n)在5-8之间,那么_INTSIZEOF(n)=8。*/
#define va_start(ap,v)( ap = (va_list)&v + _INTSIZEOF(v) )
/*va_start的定义为 &v+_INTSIZEOF(v) ,这里&v是最后一个固定参数的起始地址,再加上其实际占用大小后,就得到了第一个可变参数的起始内存地址。所以我们运行va_start(ap, v)以后,ap指向第一个可变参数在的内存地址*/
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
/*这个宏做了两个事情,
①用用户输入的类型名对参数地址进行强制类型转换,得到用户所需要的值
②计算出本参数的实际大小,将指针调到本参数的结尾,也就是下一个参数的首地址,以便后续处理。*/
#define va_end(ap) ( ap = (va_list)0 )
/*x86平台定义为ap=(char*)0;使ap不再 指向堆栈,而是跟NULL一样.有些直接定义为((void*)0),这样编译器不会为va_end产生代码,例如gcc在linux的x86平台就是这样定义的. 在这里大家要注意一个问题:由于参数的地址用于va_start宏,所以参数不能声明为寄存器变量或作为函数或数组类型. */
以下再用图来表示:
在VC等绝大多数C编译器中,默认情况下,参数进栈的顺序是由右向左的,因此,参数进栈以后的内存模型如下图所示:最后一个固定参数的地址位于第一个可变参数之下,并且是连续存储的。
|——————————————————————————|
|最后一个可变参数 | ->高内存地址处
|——————————————————————————|
...................
|——————————————————————————|
|第N个可变参数 | ->va_arg(arg_ptr,int)后arg_ptr所指的地方,
| | 即第N个可变参数的地址。
|——————————————— |
………………………….
|——————————————————————————|
|第一个可变参数 | ->va_start(arg_ptr,start)后arg_ptr所指的地方
| | 即第一个可变参数的地址
|——————————————— |
|———————————————————————— ——|
| |
|最后一个固定参数 | -> start的起始地址
|—————————————— —| .................
|—————————————————————————— |
| |
|——————————————— |-> 低内存地址处
三.printf研究
下面是一个简单的printf函数的实现,参考了中的156页的例子,读者可以结合书上的代码与本文参照。
#include "stdio.h"
#include "stdlib.h"
void myprintf(char* fmt, ...) //一个简单的类似于printf的实现,//参数必须都是int 类型
{
char* pArg=NULL; //等价于原来的va_list
char c;
pArg = (char*) &fmt; //注意不要写成p = fmt !!因为这里要对//参数取址,而不是取值
pArg += sizeof(fmt); //等价于原来的va_start
do
{
c =*fmt;
if (c != '%')
{
putchar(c); //照原样输出字符
}
else
{
//按格式字符输出数据
switch(*++fmt)
{
case 'd':
printf("%d",*((int*)pArg));
break;
case 'x':
printf("%#x",*((int*)pArg));
break;
default:
break;
}
pArg += sizeof(int); //等价于原来的va_arg
}
++fmt;
}while (*fmt != '\0');
pArg = NULL; //等价于va_end
return;
}
int main(int argc, char* argv[])
{
int i = 1234;
int j = 5678;
myprintf("the first test:i=%d",i,j);
myprintf("the secend test:i=%d; %x;j=%d;",i,0xabcd,j);
system("pause");
return 0;
}
在intel+win2k+vc6的机器执行结果如下:
the first test:i=1234
the secend test:i=1234; 0xabcd;j=5678;
四.应用
求最大值:
#include //不定数目参数需要的宏
int max(int n,int num,...)
{
va_list x;//说明变量x
va_start(x,num);//x被初始化为指向num后的第一个参数
int m=num;
for(int i=1;i {
//将变量x所指向的int类型的值赋给y,同时使x指向下一个参数
int y=va_arg(x,int);
if(y>m)m=y;
}
va_end(x);//清除变量x
return m;
}
main()
{
printf("%d,%d",max(3,5,56),max(6,0,4,32,45,533));
}
hailongchang
2006-11-15
打赏
举报
回复
#include<stdio.h>
#include<stdarg.h>
void myfunc(char* format, ...)
{
va_list ap;
va_start(ap,format);
vfprintf(stdout,format,ap);
va_end(ap);
}
int main()
{
int a = 5;
myfunc("%d",a);
return 0;
}
hailongchang
2006-11-15
打赏
举报
回复
#include<stdio.h>
#include<stdarg.h>
void myfunc(char* format, ...)
{
va_list ap;
va_start(ap,format);
vfprintf(stdout,format,ap);
va_end(ap);
fprintf(stdout,"\n");
}
int main()
{
int a = 5;
myfunc("%d",a);
return 0;
}
飞哥
2006-11-15
打赏
举报
回复
1。楼上的方法
2。对于支持C99的编译器,可以通过宏来写
weixing979
2006-11-15
打赏
举报
回复
va_list, va_arg, va_end, va_start
看帮助
用C
编写
班级成绩管理系统
每
一个
学生的包括姓名(
char
)、学号(
char
)、M门课程的成绩(float).再加上系统功能上的要求每一学生的信息还要总分和名次等。所以自然的想到要用结构体来定义每
一个
学生的信息结构。然后用链表把它们组成
一个
...
02-1 jstring与
char
*,string的转换
jstring与
char
*的转换 一、 jstring ==>
char
* jstring jstr; const
char
*str = (*env)->GetStringUTF
Char
s(env,
prompt
, 0);
printf
("%s", str); (*env)->ReleaseStringUTF
Char
s(env,
prompt
, ...
int argc,
char
* argv[] 详解
argc是命令行总的参数个数 argv[]为保存命令行参数的字符串指针,其中第0个参数是程序的全名,以后的参数为命令行后面跟的用户输入的参数,argv参数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串...
getch方法_c语言中中getch()
函数
为什么不起作用?
第一点:你既然用了getch()
函数
,在前面就应有头文件#include。因为:conio是Console Input/Output(控制台输入输出)的简写,其中定义了通过控制台进行数据输入和数据输出的
函数
,主要是一些用户通过按键盘产生的对应...
C语言中 int main(int argc,
char
*argv[])的两个参数详解
这篇文章主要介绍了C语言中 int main(int argc,
char
*argv[])的两个参数详解的相关资料,需要的朋友可以参考下: 转载自:https://www.jb51.net/article/107168.htm ...
C语言
69,369
社区成员
243,082
社区内容
发帖
与我相关
我的任务
C语言
C语言相关问题讨论
复制链接
扫一扫
分享
社区描述
C语言相关问题讨论
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章