1:当无法列出传递函数的所有实参的类型和数目时,可用省略号指定参数表void foo(...);
void foo(parm_list,...);
2:函数参数的传递原理
函数参数是以数据结构:栈的形式存取,从右至左入栈.eg:
1
#include
<
iostream
>
2
void
fun(
int
a,
)
3
{
4
int
*
temp
=
&
a;
5
temp
++
;
6
for
(
int
i
=
0
; i
<
a;
++
i)
7
{
8
cout
<<
*
temp
<<
endl;
9
temp
++
;
10
}
11
}
12
13
int
main()
14
{
15
int
a
=
1
;
16
int
b
=
2
;
17
int
c
=
3
;
18
int
d
=
4
;
19
fun(
4
, a, b, c, d);
20
system(
"
pause
"
);
21
return
0
;
22
}
#include
<
iostream
>
2
void
fun(
int
a,
)
3
{
4
int
*
temp
=
&
a;
5
temp
++
;
6
for
(
int
i
=
0
; i
<
a;
++
i)
7
{
8
cout
<<
*
temp
<<
endl;
9
temp
++
;
10
}
11
}
12
13
int
main()
14
{
15
int
a
=
1
;
16
int
b
=
2
;
17
int
c
=
3
;
18
int
d
=
4
;
19
fun(
4
, a, b, c, d);
20
system(
"
pause
"
);
21
return
0
;
22
}
Output::
1
2
3
4
3:获取省略号指定的参数
在函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。像这段代码:
1
void
TestFun(
char
*
pszDest,
int
DestLen,
const
char
*
pszFormat,
)
2
{
3
va_list args;
4
va_start(args, pszFormat);
5
_vsnprintf(pszDest, DestLen, pszFormat, args);
6
va_end(args);
7
}
8
void
TestFun(
char
*
pszDest,
int
DestLen,
const
char
*
pszFormat,
)
2
{
3
va_list args;
4
va_start(args, pszFormat);
5
_vsnprintf(pszDest, DestLen, pszFormat, args);
6
va_end(args);
7
}
8
4.va_start使argp指向第一个可选参数。va_arg返回参数列表中的当前参数并使argp指向参数列表中的下一个参数。va_end把argp指针清为NULL。函数体内可以多次遍历这些参数,但是都必须以va_start开始,并以va_end结尾。
1).演示如何使用参数个数可变的函数,采用ANSI标准形式
1
#include 〈stdio.h〉
2
#include 〈
string
.h〉
3
#include 〈stdarg.h〉
4
/*
函数原型声明,至少需要一个确定的参数,注意括号内的省略号
*/
5
int
demo(
char
,
);
6
void
main(
void
)
7
{
8
demo(
"
DEMO
"
,
"
This
"
,
"
is
"
,
"
a
"
,
"
demo!
"
,
""
);
9
}
10
/*
ANSI标准形式的声明方式,括号内的省略号表示可选参数
*/
11
int
demo(
char
�msg,
)
12
{
13
/*
定义保存函数参数的结构
*/
14
va_list argp;
15
int
argno
=
0
;
16
char
para;
17
18
/*
argp指向传入的第一个可选参数,msg是最后一个确定的参数
*/
19
va_start( argp, msg );
20
while
(
1
)
21
{
22
para
=
va_arg( argp,
char
);
23
if
( strcmp( para,
""
)
==
0
)
24
break
;
25
printf(
"
Parameter #%d is: %s/n
"
, argno, para);
26
argno
++
;
27
}
28
va_end( argp );
29
/*
将argp置为NULL
*/
30
return
0
;
31
}
#include 〈stdio.h〉
2
#include 〈
string
.h〉
3
#include 〈stdarg.h〉
4
/*
函数原型声明,至少需要一个确定的参数,注意括号内的省略号
*/
5
int
demo(
char
,
);
6
void
main(
void
)
7
{
8
demo(
"
DEMO
"
,
"
This
"
,
"
is
"
,
"
a
"
,
"
demo!
"
,
""
);
9
}
10
/*
ANSI标准形式的声明方式,括号内的省略号表示可选参数
*/
11
int
demo(
char
�msg,
)
12
{
13
/*
定义保存函数参数的结构
*/
14
va_list argp;
15
int
argno
=
0
;
16
char
para;
17
18
/*
argp指向传入的第一个可选参数,msg是最后一个确定的参数
*/
19
va_start( argp, msg );
20
while
(
1
)
21
{
22
para
=
va_arg( argp,
char
);
23
if
( strcmp( para,
""
)
==
0
)
24
break
;
25
printf(
"
Parameter #%d is: %s/n
"
, argno, para);
26
argno
++
;
27
}
28
va_end( argp );
29
/*
将argp置为NULL
*/
30
return
0
;
31
}
2)//示例代码1:可变参数函数的使用
1
#include
"
stdio.h
"
2
#include
"
stdarg.h
"
3
void
simple_va_fun(
int
start,
)
4
{
5
va_list arg_ptr;
6
int
nArgValue
=
start;
7
int
nArgCout
=
0
;
//
可变参数的数目
8
va_start(arg_ptr,start);
//
以固定参数的地址为起点确定变参的内存起始地址。
9
do
10
{
11
++
nArgCout;
12
printf(
"
the %d th arg: %d/n
"
,nArgCout,nArgValue);
//
输出各参数的值
13
nArgValue
=
va_arg(arg_ptr,
int
);
//
得到下一个可变参数的值
14
}
while
(nArgValue
!=
-
1
);
15
return
;
16
}
17
int
main(
int
argc,
char
*
argv[])
18
{
19
simple_va_fun(
100
,
-
1
);
20
simple_va_fun(
100
,
200
,
-
1
);
21
return
0
;
22
}
#include
"
stdio.h
"
2
#include
"
stdarg.h
"
3
void
simple_va_fun(
int
start,
)
4
{
5
va_list arg_ptr;
6
int
nArgValue
=
start;
7
int
nArgCout
=
0
;
//
可变参数的数目
8
va_start(arg_ptr,start);
//
以固定参数的地址为起点确定变参的内存起始地址。
9
do
10
{
11
++
nArgCout;
12
printf(
"
the %d th arg: %d/n
"
,nArgCout,nArgValue);
//
输出各参数的值
13
nArgValue
=
va_arg(arg_ptr,
int
);
//
得到下一个可变参数的值
14
}
while
(nArgValue
!=
-
1
);
15
return
;
16
}
17
int
main(
int
argc,
char
*
argv[])
18
{
19
simple_va_fun(
100
,
-
1
);
20
simple_va_fun(
100
,
200
,
-
1
);
21
return
0
;
22
}
3)//示例代码2:扩展——自己实现简单的可变参数的函数。
下面是一个简单的printf函数的实现,参考了<The C Programming Language>中的例子
1
#include
"
stdio.h
"
2
#include
"
stdlib.h
"
3
void
myprintf(
char
*
fmt,
)
//
一个简单的类似于printf的实现,
//
参数必须都是int 类型
4
{
5
char
*
pArg
=
NULL;
//
等价于原来的va_list
6
char
c;
7
8
pArg
=
(
char
*
)
&
fmt;
//
注意不要写成p = fmt !!因为这里要对
//
参数取址,而不是取值
9
pArg
+=
sizeof
(fmt);
//
等价于原来的va_start
10
11
do
12
{
13
c
=*
fmt;
14
if
(c
!=
'
%
'
)
15
{
16
putchar(c);
//
照原样输出字符
17
}
18
else
19
{
20
//
按格式字符输出数据
21
switch
(
*++
fmt)
22
{
23
case
'
d
'
:
24
printf(
"
%d
"
,
*
((
int
*
)pArg));
25
break
;
26
case
'
x
'
:
27
printf(
"
%#x
"
,
*
((
int
*
)pArg));
28
break
;
29
default
:
30
break
;
31
}
32
pArg
+=
sizeof
(
int
);
//
等价于原来的va_arg
33
}
34
++
fmt;
35
}
while
(
*
fmt
!=
'
/0
'
);
36
pArg
=
NULL;
//
等价于va_end
37
return
;
38
}
39
int
main(
int
argc,
char
*
argv[])
40
{
41
int
i
=
1234
;
42
int
j
=
5678
;
43
44
myprintf(
"
the first test:i=%d/n
"
,i,j);
45
myprintf(
"
the secend test:i=%d; %x;j=%d;/n
"
,i,
0xabcd
,j);
46
system(
"
pause
"
);
47
return
0
;
48
}
#include
"
stdio.h
"
2
#include
"
stdlib.h
"
3
void
myprintf(
char
*
fmt,
)
//
一个简单的类似于printf的实现,
//
参数必须都是int 类型
4
{
5
char
*
pArg
=
NULL;
//
等价于原来的va_list
6
char
c;
7
8
pArg
=
(
char
*
)
&
fmt;
//
注意不要写成p = fmt !!因为这里要对
//
参数取址,而不是取值
9
pArg
+=
sizeof
(fmt);
//
等价于原来的va_start
10
11
do
12
{
13
c
=*
fmt;
14
if
(c
!=
'
%
'
)
15
{
16
putchar(c);
//
照原样输出字符
17
}
18
else
19
{
20
//
按格式字符输出数据
21
switch
(
*++
fmt)
22
{
23
case
'
d
'
:
24
printf(
"
%d
"
,
*
((
int
*
)pArg));
25
break
;
26
case
'
x
'
:
27
printf(
"
%#x
"
,
*
((
int
*
)pArg));
28
break
;
29
default
:
30
break
;
31
}
32
pArg
+=
sizeof
(
int
);
//
等价于原来的va_arg
33
}
34
++
fmt;
35
}
while
(
*
fmt
!=
'
/0
'
);
36
pArg
=
NULL;
//
等价于va_end
37
return
;
38
}
39
int
main(
int
argc,
char
*
argv[])
40
{
41
int
i
=
1234
;
42
int
j
=
5678
;
43
44
myprintf(
"
the first test:i=%d/n
"
,i,j);
45
myprintf(
"
the secend test:i=%d; %x;j=%d;/n
"
,i,
0xabcd
,j);
46
system(
"
pause
"
);
47
return
0
;
48
}
另外,vfprintf是向文件中按照fmt的格式写入,不需要va_arg的参与
va_start(ap, fmt);
vfprintf(cout, fmt, ap);
va_end(ap);
vfprintf(cout, fmt, ap);
va_end(ap);