c语言中的printf()这样的有不定个参数的函数是如何实现的

谁能给个说明

首先先看到main函数中的不定参数:

1.引用:在Turbo C2.0启动过程中, 传递main()函数三个参数: argc, argv和env。
* argc: 整数, 鴐ain()的命令行参数个数。
* argv: 字符串数组。
argv[0] 为程序运行的全路径名
argv[1] 为在DOS命令行中执行程序名后的第一个字符串;
argv[2] 为执行程序名后的第二个字符串;
...
argv[argc]为NULL。
*env: 字符串数组。env[] 的每一个元素都包含ENVVAR=value形式的字符
串。其中ENVVAR为环境变量。value 为ENVVAR的对应值

#include <stdlib.h>
#include <stdio.h>
main(int argc, char *argv[], char *env[])
{
int i;
printf("%d\n", argc); /* 为什么它的输出是 1, 它到底是定义什么的,我看不明上面的解释*/
for(i=0; i<=argc; i++)
printf("argv[%d]:%s\n", i, argv[i]);
for(i=0; env[i]!=NULL; i++)
printf(" env[%d]:%s\n", i, env[i]);
}
argc, argv, env是在main()函数之前被赋值的,编译器生成的可执行文件,main()不是真正的入口点,而是一个标准的函数,这个函数名与具体的操作系统有关。

就想到其他函数是否能实现一样的功能,查询了相关资料,基本上都是利用STDARG.H中的

#define va_start(ap, parmN) (ap = ...)
#define va_arg(ap, type) (*((type *)(ap))++)
#define va_end(ap)

定义如下:

typedef char * va_list;

#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end

#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )

修改他人程序如下:

void average(int first,...)
{int i=first;
va_list maker;
va_start(maker,first);
while(i!=-1){ printf("%p: %d\n",maker,i);
i=va_arg(maker,int);
}
}
void main(void)
{
average(2,3,4,4,-1);
}

运行结果:

FFCE: 2
FFD0: 3
FFD2: 4
FFD4: 4

这个程序显示函数参数的地址相差2个字节

所以可以改写为:

void x(char *n,...)
{int *p;

p=&n;
while(*p!=-1)
{printf("%p:%s\n",p,*p,*p);
p+=sizeof(char);}}
void main()
{x("g","hfd","gfg","vsds",-1);}

运行结果:

FFD2:g
FFD4:hfd
FFD6:gfg
FFD8:vsds

不必通过宏va_start,va_arg,va_end实现
温馨提示:内容为网友见解,仅供参考
第1个回答  2008-04-03
从格式控制字符串中提取格式控制字符,再根据格式控制字符去查找后的参数。
第2个回答  2020-01-03
首先先看到main函数中的不定参数:
1.引用:在Turbo
C2.0启动过程中,
传递main()函数三个参数:
argc,
argv和env。
*
argc:
整数,
鴐ain()的命令行参数个数。
*
argv:
字符串数组。
argv[0]
为程序运行的全路径名
argv[1]
为在DOS命令行中执行程序名后的第一个字符串;
argv[2]
为执行程序名后的第二个字符串;
...
argv[argc]为NULL。
*env:
字符串数组。env[]
的每一个元素都包含ENVVAR=value形式的字符
串。其中ENVVAR为环境变量。value
为ENVVAR的对应值
#include
#include
main(int
argc,
char
*argv[],
char
*env[])
{
int
i;
printf("%d\n",
argc);
/*
为什么它的输出是
1,
它到底是定义什么的,我看不明上面的解释*/
for(i=0;
i<=argc;
i++)
printf("argv[%d]:%s\n",
i,
argv[i]);
for(i=0;
env[i]!=NULL;
i++)
printf("
env[%d]:%s\n",
i,
env[i]);
}
argc,
argv,
env是在main()函数之前被赋值的,编译器生成的可执行文件,main()不是真正的入口点,而是一个标准的函数,这个函数名与具体的操作系统有关。
就想到其他函数是否能实现一样的功能,查询了相关资料,基本上都是利用STDARG.H中的
#define
va_start(ap,
parmN)
(ap
=
...)
#define
va_arg(ap,
type)
(*((type
*)(ap))++)
#define
va_end(ap)
定义如下:
typedef
char
*
va_list;
#define
va_start
_crt_va_start
#define
va_arg
_crt_va_arg
#define
va_end
_crt_va_end
#define
_crt_va_start(ap,v)
(
ap
=
(va_list)_ADDRESSOF(v)
+
_INTSIZEOF(v)
)
#define
_crt_va_arg(ap,t)
(
*(t
*)((ap
+=
_INTSIZEOF(t))
-
_INTSIZEOF(t))
)
#define
_crt_va_end(ap)
(
ap
=
(va_list)0
)
修改他人程序如下:
void
average(int
first,...)
{int
i=first;
va_list
maker;
va_start(maker,first);
while(i!=-1){
printf("%p:
%d\n",maker,i);
i=va_arg(maker,int);
}
}
void
main(void)
{
average(2,3,4,4,-1);
}
运行结果:
FFCE:
2
FFD0:
3
FFD2:
4
FFD4:
4
这个程序显示函数参数的地址相差2个字节
所以可以改写为:
void
x(char
*n,...)
{int
*p;
p=&n;
while(*p!=-1)
{printf("%p:%s\n",p,*p,*p);
p+=sizeof(char);}}
void
main()
{x("g","hfd","gfg","vsds",-1);}
运行结果:
FFD2:g
FFD4:hfd
FFD6:gfg
FFD8:vsds
不必通过宏va_start,va_arg,va_end实现
第3个回答  2008-04-03
int _Cdecl printf(const char *__format, ...);

Pointer to a list of arguments One of a series of arguments to which the functions apply a format specifier contained in *format Buffer where function writes the string Format string Stream where the functions output the formatted data
第4个回答  2020-05-18
//32
bit
汇编调用printf
//call
printf
(fmt,a1,a1,a3,a4.....an)
;调用的数据压入栈,由于宽度不知道,所以用伪代码表示.
push
a5
push
a4
push
a3
push
a2
push
a1
push
offset
fmt
call
printf
sub
esp,sizeof(an)+..........+sizeof(a4)+sizeof(a3)+sizeof(a2)+sizeof(a1)
printf
的c实现
//实际上
用汇编的时候,跳过返回地址就是所有参数的首地址
//mov
ebx
,dword
ptr
esp[8]
;
//fmt
的地址
//mov
esi,
dowrd
ptr
esp[12]
//a1的地址
char**pvarlist=
&fmt;//fmt
在堆栈最低端。是个地址,所以他的地址就是所有参数的首地址
pvarlist++;
for(
i=0;i
评论
0
0
加载更多
相似回答