#include<stdlib.h>
#include<stdio.h>
#include<stdarg.h>
/*
1. 使用va_list va_start va_arg va_end实现可变参数
*/
void simple_va_fun(int i, ...) {
va_list arguments;
int j = 0;
int k, m;
va_start(arguments, i);
j = va_arg(arguments, int);
m = va_arg(arguments, int);
va_end(arguments);
printf("%d,%d,%d\n",i,j,m);
}
/*
2. 固定参数函数
*/
void fixed_args_func(char x, int a, double b, char *c)
{ //打印参数在栈中的地址
printf("x = 0x%p\n", &x);
printf("a = 0x%p\n", &a);
printf("b = 0x%p\n", &b);
printf("c = 0x%p\n", &c);
}
/*
3. 实现自己的可变参数,实则是按顺序从栈中取出参数的值
*/
void var_args_func(const char * fmt, ...) {
char* ap;
ap = (char *)&fmt + sizeof(fmt);
int* int_ap = (int *)ap;
printf("first:%d\n",*int_ap);
int_ap = int_ap + 1;
printf("second:%d\n",*int_ap);
int_ap = int_ap + 1;// string start index
char* c_ptr = (char*)int_ap;
char* str = (char* )*int_ap;
printf("&int_ap = 0x%p\n",int_ap);
printf("&c_ptr = 0x%p\n", c_ptr);
printf("&str = 0x%p\n",str);
//栈里面存储的是指向字符串"helloworld的指针",即二级字符指针
printf("third1: %s\n",str);
printf("third2: %s\n", *(char **)int_ap);
}
//stdarg.h 中提供的标准可变参数宏
void std_vararg_func(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
printf("%d\n", va_arg(ap, int));
printf("%f\n", va_arg(ap, double));
printf("%s\n", va_arg(ap, char*));
va_end(ap);
}
int main() {
//fixed_args_func('a',17, 5.40, "hello world");
//char* p = "xiongwei";
//printf("%d\n",sizeof(p));
var_args_func("%d %d %s\n", 4, 5, "helloworld");
printf("--------------------------------------\n");
std_vararg_func("%d %f %s\n", 4, 5.4, "helloworld");
system("pause");
return 0;
}
对比一下 std_vararg_func和var_args_func的实现,va_list似乎就是char*, va_start似乎就是((char*)&fmt) + sizeof(fmt),va_arg似乎就是得到下一个参数的首地址。没错,多数平台下stdarg.h中va_list, va_start和var_arg的实现就是类似这样的。一般stdarg.h会包含很多宏,看起来比较复杂。在有的系统中stdarg.h的实现依赖some special functions built into thethe compilation system to handle variable argument lists and stack allocations,多数其他系统的实现与下面很相似:(Visual C++ 6.0的实现较为清晰,因为windows上的应用程序只需要在windows平台间做移植即可,没有必要考虑太多的平台情况)。
output://
first:4
second : 5
& int_ap = 0x003EF968
& c_ptr = 0x003EF968
& str = 0x013780D4
third1 : helloworld
third2 : helloworld
--------------------------------------
4
5.400000
helloworld
实现Printf()函数:
#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( "thefirst test:i=%d", i, j );
myprintf( "thesecend test:i=%d; %x;j=%d;", i, 0xabcd, j );
system( "pause" );
return(0);
}
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。