可变参数函数(一)

一个函数可以接受不定数的参数个数,这就是可变参数函数,比较常见的比如printf(),scanf();

printf(const char* format,…);
printf(“%d”,i);
printf(“%s”,s);
printf(“the number is %d,stirng is :%s”,i,s);

变量参数函数的简单实现:

#include<stdio.h>
#include<stdarg.h>int simple(int num,...)
{int i,result = 0;va_list vl;va_start(vl,num);printf("num:%d, vl:%d\n",num,*vl);for(i = 0; i < num - 1 ; i++){result = va_arg(vl,int);printf("in for result:%d ,*vl:%d\n",result,*vl);}va_end(vl);return result;
}int main()
{int sum = simple(5,1,2,3,4,5);if(0 == sum){printf("simple failed\n");}else{printf("simple success! sum = %d\n",sum);    }return 0;
}

结果如下:

exbot@ubuntu:~/wangqinghe/DeBug/20190702$ ./VA

num:5, vl:1020625376

in for result:1 ,*vl:1020625376

in for result:2 ,*vl:1020625376

in for result:3 ,*vl:1020625376

in for result:4 ,*vl:1020625376

simple success! sum = 4

sum.c
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>double add(int n,...)
{//printf("add...\n");int i = 0;double sum = 0;va_list argptr;  va_start(argptr,n);  //初始化argptrfor(i = 0 ; i < n; i++) ////对每个可选参数,读取类型为int的参数
    {sum += va_arg(argptr,int);        //累加到sum中
    }va_end(argptr);    printf("add_sum = %f\n",sum);return sum;
}int main(int argc,char **argv)
{double sum = 0;int *p = malloc(argc * sizeof(int));int i;for(i = 1; i < argc; i++)        {        p[i] = atoi(argv[i]);    printf("p[%d] = %d\n",i,p[i]);}sum = add(argc,p[1]);printf("sum = %f\n",sum);sum = add(argc,p[1],p[2]);printf("sum = %f\n",sum);sum = add(argc,p[1],p[2],p[3]);printf("sum = %f\n",sum);        free(p);return 0;
}

输出结果;

exbot@ubuntu:~/wangqinghe/DeBug/20190702$ ./sum 10 20 30

p[1] = 10

p[2] = 20

p[3] = 30

add_sum = 239745405.000000

sum = 239745405.000000

add_sum = 56.000000

sum = 56.000000

add_sum = 69.000000

sum = 69.000000

 

相关函数介绍:

可变函数列表的实现由几个宏组成的,在文件#include<stdarg.h>中。

va_list 定义某个变量,内核的定义如下:

typedef char *va_list;  //字符指针类型

va_start(ap,type) 开始获取可变参数列表中第一个参数(…里面的第一个),也就是跳过第一个参数。(所以以上的第一个输出是个随机值)。

#ifndef __sparc__
#define va_start(AP, LASTARG)                         \(AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))//ap指向下一个参数,lastarg不变
#else
#define va_start(AP, LASTARG)                         \(__builtin_saveregs (),                        \AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) //跳过下第一个参数,指向第二个参数内存地址
#endif//对type向上取整 取int的整 4,然后乘上int整型4的倍数
#define __va_rounded_size(TYPE)  \(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

Va_arg(args,int)循环获取可变参数列表中的参数,args指向下一个参数地址,返回的是当前参数地址。

//  first=va_arg(args,int)
#define va_arg(AP, TYPE)                        \//ap指向下一个类型的参数(AP += __va_rounded_size (TYPE),                    \//返回ap - sizeof(type)参数,即前一个参数*((TYPE *) (AP - __va_rounded_size (TYPE))))//对type向上取整 取int的整 4,然后乘上int整型4的倍数
#define __va_rounded_size(TYPE)  \(((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))

最后一个va_end(ap)结束标志,在程序中只是作为一个可变参数列表的结束标识,在stdarg.h中仅仅定义了一下,没有实现代码部分。

转载于:https://www.cnblogs.com/wanghao-boke/p/11119490.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/385013.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux内核线程kernel thread详解--Linux进程的管理与调度

内核线程为什么需要内核线程Linux内核可以看作一个服务进程(管理软硬件资源&#xff0c;响应用户进程的种种合理以及不合理的请求)。 内核需要多个执行流并行&#xff0c;为了防止可能的阻塞&#xff0c;支持多线程是必要的。 内核线程就是内核的分身&#xff0c;一个分身可以处…

可变参数函数(二)

函数样例&#xff1a; #include<stdio.h> #include<stdlib.h> #include<stdarg.h>double add(int n,...) {int i 0;double sum 0;va_list argptr;va_start(argptr,n);for(i 0 ; i < n; i){double d va_arg(argptr,double);printf("%d argument …

Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16)

在2.6.24之后这个结构体有了较大的变化&#xff0c;此处先说一说2.6.16版本的sk_buff&#xff0c;以及解释一些问题。一、先直观的看一下这个结构体~~~~~~~~~~~~~~~~~~~~~~在下面解释每个字段的意义~~~~~~~~~~~[cpp] view plaincopyprint?struct sk_buff { /* These…

可变参数输出(三)

Linux C关于输出函数的定义&#xff1a; int printf(const char *format,…); int vprintf(const char * format,va_list ap); int vfprintf(FILE *stream,cosnt char *format,va_list ap); int vsprintf(char *str,const char *format,va_list ap); int vsnprintf(char *str,s…

最常用的设计模式---适配器模式(C++实现)

适配器模式属于结构型的设计模式&#xff0c;它是结构型设计模式之首&#xff08;用的最多的结构型设计模式&#xff09;。 适配器设计模式也并不复杂&#xff0c;适配器它是主要作用是将一个类的接口转换成客户希望的另外一个接口这样使得原本由于接口不兼容而不能一起工作的那…

Linux 简单打印日志(二)

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> //#include<windows.h> #include <unistd.h> // linux下头文件#define FILE_MAX_SIZE (1024*1024)void get_local_time(char* buffer){time_t rawtime;struct …

程序随笔——C++实现的一个线程池

1.线程池简介 我们知道在线程池是一种多线程处理形式&#xff0c;处理过程中我们将相应的任务提交给线程池&#xff0c;线程池会分配对应的工作线程执行任务或存放在任务队列中&#xff0c;等待执行。 面向对象编程中&#xff0c;创建和销毁对象是需要消耗一定时间的&#xff0…

线程池原理及创建并C++实现

本文给出了一个通用的线程池框架&#xff0c;该框架将与线程执行相关的任务进行了高层次的抽象&#xff0c;使之与具体的执行任务无关。另外该线程池具有动态伸缩性&#xff0c;它能根据执行任务的轻重自动调整线程池中线程的数量。文章的最后&#xff0c;我们给出一个简单示例…

Linux 打印简单日志(一)

简单日志输出&#xff1a; #include<stdio.h> #include<string.h> #include<stdlib.h>void write(char* filename,char* szStr){FILE* fp;fp fopen(filename,"at");if(fp ! NULL){fwrite(szStr,256,1,fp); //fclose(fp);fp NULL;} }int main(int…

c++简单线程池实现

线程池&#xff0c;简单来说就是有一堆已经创建好的线程&#xff08;最大数目一定&#xff09;&#xff0c;初始时他们都处于空闲状态&#xff0c;当有新的任务进来&#xff0c;从线程池中取出一个空闲的线程处理任务&#xff0c;然后当任务处理完成之后&#xff0c;该线程被重…

Linux 打印可变参数日志

实现了传输进去的字符串所在的文档&#xff0c;函数和行数显示功能。 实现了将传入的可变参数打印到日志功能。 #include<stdio.h> #include<stdarg.h> #include<string.h>const char * g_path "/home/exbot/wangqinghe/log.txt"; #define LOG(fm…

C++强化之路之线程池开发整体框架(二)

一.线程池开发框架 我所开发的线程池由以下几部分组成&#xff1a; 1.工作中的线程。也就是线程池中的线程&#xff0c;主要是执行分发来的task。 2.管理线程池的监督线程。这个线程的创建独立于线程池的创建&#xff0c;按照既定的管理方法进行管理线程池中的所有线程&#xf…

vfprintf()函数

函数声明&#xff1a;int vfprintf(FILE *stream, const char *format, va_list arg) 函数参数&#xff1a; stream—这是指向了FILE对象的指针&#xff0c;该FILE对象标识了流。 format—c语言字符串&#xff0c;包含了要被写入到流stream中的文本。它可以包含嵌入的format标签…

Makefile(二)

将生产的.o文件放进指定的文件中&#xff08;先创建该文件夹&#xff09; src $(wildcard ./*.cpp) obj $(patsubst %.cpp,./output/%.o,$(src))target test$(target) : $(obj)g $(obj) -o $(target) %.o: %.cppg -c $< -o output/$.PHONY:clean clean:rm -f $(target) $…

TCP粘包问题分析和解决(全)

TCP通信粘包问题分析和解决&#xff08;全&#xff09;在socket网络程序中&#xff0c;TCP和UDP分别是面向连接和非面向连接的。因此TCP的socket编程&#xff0c;收发两端&#xff08;客户端和服务器端&#xff09;都要有成对的socket&#xff0c;因此&#xff0c;发送端为了将…

UML类图符号 各种关系说明以及举例

UML中描述对象和类之间相互关系的方式包括&#xff1a;依赖&#xff0c;关联&#xff0c;聚合&#xff0c;组合&#xff0c;泛化&#xff0c;实现等。表示关系的强弱&#xff1a;组合>聚合>关联>依赖 相互间关系 聚合是表明对象之间的整体与部分关系的关联&#xff0c…

寻找数组中第二大数

设置两个数值来表示最大数和第二大数&#xff0c;在循环比较赋值即可 //找给定数组中第二大的数int get_smax(int *arr,int length) {int max;int smax;if(arr[0] > arr[1]){max arr[0];smax arr[1];}else{max arr[1];smax arr[0];}for(int i 2; i < length; i){if(…

timerfd API使用总结

timerfd 介绍 timerfd 是在Linux内核2.6.25版本中添加的接口&#xff0c;其是Linux为用户提供的一个定时器接口。这个接口基于文件描述符&#xff0c;所以可以被用于select/poll/epoll的场景。当使用timerfd API创建多个定时器任务并置于poll中进行事件监听&#xff0c;当没有可…

#if/#else/#endif

在linux环境下写c代码时会尝试各种方法或调整路径&#xff0c;需要用到#if #include<stdio.h>int main(){int i; #if 0i 1; #elsei 2; #endifprintf("i %d",i);return 0; } 有时候会调整代码&#xff0c;但是又不是最终版本的更换某些值&#xff0c;就需要注…

内存分配调用

通过函数给实参分配内存&#xff0c;可以通过二级指针实现 #include<stdio.h> #incldue<stdlib.h>void getheap(int *p) //错误的模型 {p malloc(100); }void getheap(int **p) //正确的模型 {*p malloc(100); } int main() {int *p NULL;getheap(&p);free(p…