c语言可变参

一、什么是可变参数

在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: 
int printf(const
char* format,…),int scanf(const char
*format,…);它除了有一个参数format固定以外,后面跟着的参数的个数和类型是可变的(用三个点“…”做参数占位符),实际调用时可以有以下的形式: 
          
printf(“%d”,i);  printf(“%d,%c”,i,j);

二、C语言---简单的可变参数例子(实现思想)

       
1、整型数据的输出


#include <stdio.h>
#include <stdarg.h>
void ar_cnt(int cnt,...);
void ar_cst(char const *s,...);
int main(int argc, char* argv[])
{
int in_size =_INTSIZEOF(int);
printf("int_size=%d\n",in_size);
ar_cnt(5,1,2,3,4);
return 0;
}
void ar_cnt(int cnt,...)
{
int value1=0;
int i=0;
int arg_cnt = cnt;
va_list arg_ptr;
va_start(arg_ptr,cnt);
for(i=0;i<cnt;i++)
{
value1=va_arg(arg_ptr,int);
printf("posation %d=%d\n",value1,i+1);
}
va_end(arg_ptr);
}

运行结果:

2、字符串的输出


#include <stdio.h>
#include <stdarg.h>

void PrintLines(char *first,...)
{
char *str;
va_list v1;
str = first;
va_start(v1,first);
do
{
printf("%s\n",str);
str=va_arg(v1,char*);
} while (str != NULL );
va_end(v1);
}

int main(int argc, char* argv[])
{
PrintLines("First","Second","Third","Fourth",NULL);
return 0;
}

运行结果:

          
3、找出最大数


#include <stdio.h>
#include <stdarg.h>
int FindMax(int amount,...)
{
int i,val,great;
va_list v1;
va_start(v1,amount);
great=va_arg(v1,int);
for(i=1;i<amount;i++)
{
val=va_arg(v1,int);
great=(great>val)?great:val;
}
va_end(v1);
return great;
}

int main(int argc, char* argv[])
{
int max=FindMax(5,100,20,456,102,4,300);
printf("The Max one is %d\n",max);
return 0;
}

运行结果:

三、对va_arg,va_list,va_start,va_end,_INTSIZEOF剖析

  • 内存对齐  #define _INTSIZEOF(n)
    ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1)

                
    具体请参考:http://blog.csdn.net/swell624/article/details/3210779

  • 可变参数用到以下宏函数  
        <1>原型: void
    va_start(va_list arg_ptr,prev_param);

功能:以固定参数的地址为起点确定变参的内存起始地址,获取第一个参数的首地址

返回值:无

<2>原型:va_list
类型的变量,va_list arg_ptr ,这个变量是指向参数地址的指针,因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。

<3>原型:type
va_arg(va_list arg_ptr,type);

功能:获取下一个参数的地址

返回值:根据传入参数类型决定返回值类型

<4>原型:void 
va_end(va_list arg_ptr);

功能:将arg_ptr指针置0

返回值:无

  • 使用可变参数应该有以下步骤:

⑴在程序中将用到以下这些宏:

void va_start( va_list arg_ptr, prev_param
);

type va_arg( va_list arg_ptr, type );

void va_end( va_list arg_ptr );

va在这里是variable-argument(可变参数)的意思.

这些宏定义在stdarg.h中,所以用到可变参数的程序应该包含这个头文件.

⑵函数里首先定义一个va_list型的变量,这里是arg_ptr,这个变量是指向参数地址的指针.因为得到参数的地址之后,再结合参数的类型,才能得到参数的值。

⑶然后用va_start宏初始化⑵中定义的变量arg_ptr,这个宏的第二个参数是可变参数列表的前一个参数,也就是最后一个固定参数。

⑷然后依次用va_arg宏使arg_ptr返回可变参数的地址,得到这个地址之后,结合参数的类型,就可以得到参数的值。然后进行输出。

⑸设定结束条件,这里的条件就是判断参数值是否为-1。注意被调的函数在调用时是不知道可变参数的正确数目的,程序员必须自己在代码中指明结束条件。至于为什么它不会知道参数的数目,读者在看完下面这几个宏的内部实现机制后,自然就会明白。

三、参考文献: 
       http://www.chineselinuxuniversity.net/articles/26262.shtml

http://www.cnblogs.com/wangyonghui/archive/2010/07/12/1776068.html

http://www.2cto.com/kf/201204/129038.html

时间: 2024-10-10 20:52:39

c语言可变参的相关文章

C语言可变参简介

C语言可变参简介 我们在C语言编程中会遇到一些参数个数可变的函数,例如printf()这个函数,它的定义是这样的:     int printf( const char* format, ...); 它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法:     printf("%d",i);      printf("%s",s);     printf("the number is %d ,strin

C语言之 认识可变参数

printf()的原型是int printf(const char *fmt, ...);后面三个 . 表示C语言的变参. 那么什么是变参?它有什么功能和作用呢? 变参就是参数不确定,可以随意根据需要来改变的参数. 我们先举一个固定参数列表的函数: int swap(int a,int b) { int c; c=a; a=b; b=c; return a; } 这是随便写的一个函数,虽然由于里面全都是局部变量的原因所以并不能交换参数,但是这个函数的形式还是挺不错的. 再举例一个可变参数列表函数

由 snprintf 引发的一个问题

所有代码在如下平台编译运行: gcc 4.1.2 kernel 2.6 当使用32位编译如下代码时,会出现乱码: long long n = 0x123456LL; const char* s = "helloworld"; char buff[512] = {0}; snprintf(buff, 512, "n=%d&s=%s\n", n, s); printf("%s\n", buff); 使用 gcc -m32 ./main.c -

C语言变参问题

C++中有函数重载这种方法,以供我们调用时要可以不确定实参的个数,其实 C 语言也可以,而且更高明! 我们在stdio.h 中可以看到 printf() 函数的原型: int printf(char * format,...) 事实上,我们如果要写这样的函数也可以类似的写,那么在定义函数时用上这个符号“ ... ” ,它叫占位符,喊它 “ 三个点 ” 也可以,只要你愿意!那么我可以这样定义我的函数: fun(int a,...) { } 这是个空函数,它是什么都不做的,光这样写还不行的,具体应该

C语言函数的变参实用与分析

实现变参传递的关键是: 传入参数在内存中是连续分布的. #define va_list void* #define va_arg(arg, type) *(type*)arg; arg = (char*)arg + sizeof(type); #define va_start(arg, start) arg = (va_list)(((char*)&(start)) + sizeof(start)) #define va_end(arg) arg = (void*)0 这四个宏其实是c语言定义好

C语言之linux内核可变参实现printf,sprintf

昨天,我发表了一篇用可变参实现的fprintf函数,其实说实话还不完全是可变参实现的,因为用到了FILE * 这样的指针,需要包含stdio.h这个头文件才能实现这个函数,今天我们就来看看,如何抛弃stdio.h,全0开始实现printf , sprintf ,当然,这段代码是我在linux内核里面获取的,再经过我本人修改,移植,在DevC++这个编译环境中通过测试.我们来看看代码: #include <stdarg.h> #define NULL 0 //如果字符串中为数字,则返回数字 st

C语言之可变参实现scanf函数

既然有printf函数可变参实现,那就一定有scanf函数的可变参实现.废话不多说,源码奉上: 本源码不过多分析,如要明白原理,请翻本博客以往的文章看说明. 欢迎关注新浪微博:http://weibo.com/u/1896293701/home?topnav=1&wvr=6 #include <stdio.h> #include <stdarg.h> int myscanf(const char *fmt , ...) ; int main(void) { int num

C语言可变参数函数实现原理

一.可变参数函数实现原理 C函数调用的栈结构: 可变参数函数的实现与函数调用的栈结构密切相关,正常情况下C的函数参数入栈规则为__stdcall, 它是从右到左的,即函数中的最右边的参数最先入栈. 本文地址:http://www.cnblogs.com/archimedes/p/variable-parameter.html,转载请注明源地址. 例如,对于函数: void fun(int a, int b, int c) { int d; ... } 其栈结构为 0x1ffc-->d 0x200

根据需要分等级的打印日志(C语言)

在程序遇到问题调试时,有时候需要打印一些中间变量,观察完调试完又需要把这些打印注释掉,感觉很麻烦.所以写了一个小程序,可以设置打印日志等级. 在主程序设置要打印的日志等级debug,就把相应的等级的日志全部打出来观察. 程序用到了va_list(在C语言中解决变参问题的一组宏),相关知识可参考http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html(注意链接文章正确的程序在评论中) . 直接上主程序:main.cpp 1 #