_vsntprintf函数相关

abcllla 2008-09-27 08:09:43
_vsntprintf函数由哪个头文件包含原型?
这个函数可解决未知参数数目函数的问题。请问各位前辈它是怎么实现的?大概就行。
...全文
731 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
weakker 2010-05-21
  • 打赏
  • 举报
回复
嗖嘎~~明白了好多!
wenh7788 2009-08-01
  • 打赏
  • 举报
回复
结贴了,留个名下次好找.
哈哈哈
bysdy 2008-09-29
  • 打赏
  • 举报
回复
上面的堆栈貌似乱掉了饿~~~
|high| |'/0'|
|...| |'d'|
|b | |'%'|
|a |--arg |'x'|
|fmt|----------|'%'|
|...| |...|
|low| |low|
bysdy 2008-09-29
  • 打赏
  • 举报
回复
顶4楼的~~~大概就是那样了~~~
举个最简单的
printf("%x%d",a,b);
那么堆栈情况就是
push b
push a
push fmt
call printf
┃ HIGH ┃ ┃ HIGH ┃
┃ ... ┃ ┃ ... ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
┃ ┃ ┃ '\0' ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
┃ b ┃ ┃ d ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
arg = ┃ a ┃ ┃ % ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
┃ fmt ──╂────┐ ┃ x ┃
┣━━━━━━━━━━┫ │ ┣━━━━━━━━━━┫
┃ ┃ └──→ ┃ % ┃
┣━━━━━━━━━━┫ ┣━━━━━━━━━━┫
┃ ... ┃ ┃ ... ┃
┃ LOW ┃ ┃ LOW ┃
然后在printf()的函数内
定义一个指针arg指向a也就是(&fmt) + 4;
然后调用令一个函数分析格式假设是vsprintf(char *buf, const char *fmt, va_list args)
fmt就是printf内的那个“%x%d”,args就是那个指向a,b的指针arg,buf这是缓冲字符串
然后在vsprintf函数内循环判断fmt的内容,就和4楼代码中的switch(*fmt)一样,判断输出的类型,比如这里第一个是x,那么就把a转换成16进制以字符形式输出到buf缓冲去,继续判断下一个,'d'则说明是一个10进制的int型,同样转换成10进制以字符形式输出到buf缓冲去其他的格式也一样,而args指针则根据是'c','s','d'来判断移动多少~~~
最后一直到*fmt='/0',说明全部都处理完毕,再返回到printf,在调用系统调用或是其他的来输出buf中的内容就行了

说的有点混乱哈貌似,不过结合4楼的代码应该看的懂吧嘿嘿~~~
K行天下 2008-09-28
  • 打赏
  • 举报
回复
可以看GCC的源代码
野男孩 2008-09-28
  • 打赏
  • 举报
回复
重点是要理解参数在堆栈中得表示,弄清楚了堆栈中的数据布局,要理解变参就没问题了。
hmsuccess 2008-09-28
  • 打赏
  • 举报
回复
你可以参考:

#define __va_rounded_size(TYPE) \
(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

#define va_start(AP, LASTARG) \
(__builtin_saveregs (), \
AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))

int printk(const char *fmt, ...)
{
char* args;
int i;

va_start(args, fmt);
i=vsprintf(buf,fmt,args);
va_end(args);
__asm__("push %%fs\n\t"
"push %%ds\n\t"
"pop %%fs\n\t"
"pushl %0\n\t"
"pushl $_buf\n\t"
"pushl $0\n\t"
"call _tty_write\n\t"
"addl $8,%%esp\n\t"
"popl %0\n\t"
"pop %%fs"
::"r" (i):"ax","cx","dx");
return i;
}

int vsprintf(char *buf, const char *fmt, va_list args)
{
int len;
int i;
char * str;
char *s;
int *ip;

int flags; /* flags to number() */

int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */

for (str=buf ; *fmt ; ++fmt) {
if (*fmt != '%') {
*str++ = *fmt;
continue;
}

/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}

/* get field width */
field_width = -1;
if (is_digit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}

/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (is_digit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}

/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
qualifier = *fmt;
++fmt;
}

switch (*fmt) {
case 'c':
if (!(flags & LEFT))
while (--field_width > 0)
*str++ = ' ';
*str++ = (unsigned char) va_arg(args, int);
while (--field_width > 0)
*str++ = ' ';
break;

case 's':
s = va_arg(args, char *);
len = strlen(s);
if (precision < 0)
precision = len;
else if (len > precision)
len = precision;

if (!(flags & LEFT))
while (len < field_width--)
*str++ = ' ';
for (i = 0; i < len; ++i)
*str++ = *s++;
while (len < field_width--)
*str++ = ' ';
break;

case 'o':
str = number(str, va_arg(args, unsigned long), 8,
field_width, precision, flags);
break;

case 'p':
if (field_width == -1) {
field_width = 8;
flags |= ZEROPAD;
}
str = number(str,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
break;

case 'x':
flags |= SMALL;
case 'X':
str = number(str, va_arg(args, unsigned long), 16,
field_width, precision, flags);
break;

case 'd':
case 'i':
flags |= SIGN;
case 'u':
str = number(str, va_arg(args, unsigned long), 10,
field_width, precision, flags);
break;

case 'n':
ip = va_arg(args, int *);
*ip = (str - buf);
break;

default:
if (*fmt != '%')
*str++ = '%';
if (*fmt)
*str++ = *fmt;
else
--fmt;
break;
}
}
*str = '\0';
return str-buf;
}
likefermat 2008-09-27
  • 打赏
  • 举报
回复
像printf之类的语句,确实功能很强大,他可以实现可变参数的输出,
他的原理是这样的:
首先根据printf里面的字符串参数的%可以确定参数的个数,
如printf("%d %c %s %%",a,b,c);
那么系统可以自动的判断有3参数,
%d代表一个,%c代表一个,%s代表一个,然后就是如何知道这3个参数的地址问题,
函数参数入栈的时候,一般是从右往左的顺序,
并且这些参数的地址是连续的,于是,可以根据这个来计算这些参数的地址。
看看下面这个例子,是可以求无限个数的最大值的超级max函数,也是利用了这个原理,如:
#include "stdio.h"
int Max(int n, ...)
{
int *p = &n + 1;//参数个数的地址偏移1个单位(4个字节)
int ret = *p;//从这个p指向的地址开始,其实保存了实际参数的地址值,
for (int i=0; i<n; i++)//连续n个数的地址连续存放
{
if (ret < *(p + i))
ret = *(p + i);
}
return ret;
}
void main()
{
printf("max=%d",Max(5,6,1,9,3,8));
}

这个函数调用的时候,第一个参数表示要比较的数的个数,后面的列表表示这些数,其实后面列表数的个数也可以大于n但是
程序只会比较前n个。

更深一层的原理,还等高人补充.
帅得不敢出门 2008-09-27
  • 打赏
  • 举报
回复
<stdio.h> and <stdarg.h>
int _vsnprintf(
char *buffer,
size_t count,
const char *format,
va_list argptr
);


bayuan0414 2008-09-27
  • 打赏
  • 举报
回复
vsntprintf没见过 vsnprintf倒是见过
vsnprintf定义在 stdarg.h和stdio.h函数中
给个vsnprintf的实现

int __cdecl _vsnprintf (
char *string,
size_t count,
const char *format,
va_list ap
)
#endif /* _COUNT_ */

{
FILE str;
REG1 FILE *outfile = &str;
REG2 int retval;

_ASSERTE(string != NULL);
_ASSERTE(format != NULL);

outfile->_flag = _IOWRT|_IOSTRG;
outfile->_ptr = outfile->_base = string;
#ifndef _COUNT_
outfile->_cnt = MAXSTR;
#else /* _COUNT_ */
outfile->_cnt = count;
#endif /* _COUNT_ */

retval = _output(outfile,format,ap );
_putc_lk('\0',outfile);

return(retval);
}



这种库函数级别的 还是多关注下用法
实现, 还是等你到了那步在关注

70,037

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧