可变参数源码的剖析和自己的理解
来源:互联网 发布:java sort 编辑:程序博客网 时间:2024/06/05 02:29
在日常写代码时,经常会用到“printf”函数,而printf函数可以传递多个参数,可以1个,2个,多个。而我们写函数时,会注意到自己定义的形参数量是已经定义好的,对比printf函就会发现该函数参数数量却是传递任意个数都可以输出的。如:
printf("%d\n", 2017); printf("%s\n","I'm fine."); printf("%d %s\n", 2017,"I'm fine.");
查阅一下printf函数原型:
int printf ( const char * format, ... );
这时,我们发现参数列表里里有“…”。因此,我们就要讨论一下可变参数,注意:可变参数中参数值至少为1。 而要使用可变参数,就要先了解这些宏:
va_list arg; void va_start( va_list arg_ptr, prev_param ); type va_arg( va_list arg_ptr, type ); void va_end( va_list arg_ptr );
而这些宏应该怎么用呢,我就用一个简单的求最大值算法,在代码中注释来给大家解释下。本来顺手打了讲解的,想想自己还是一只小菜鸡呢,赶紧改成解释了呢……
#define _CRT_SECURE_NO_WARNINGS//此处用于在VS2015中防止编译警告#include<stdarg.h>//调用上述宏所需要声明的头文件#include<stdio.h>//输入、输出函数所需要声明的头文件int CalculateMax(int n, ...){ int max = 0; int i = 0; int middle = 0;//存放表达式:va_arg(arg,int)的值 va_list arg;// 定义一个名称为arg的指针 va_start(arg, n);//用于指明arg是指针名,n代表第一个参数,用于表示起始端 max = va_arg(arg, int); while (i < n - 1) { if (max < (middle = va_arg(arg, int)))//如果middle = va_arg(arg, int)的值小于max,进入判断 { max = middle; } i++; } va_end(arg); return max;}int main(){ int result = CalculateMax(5, -5, -9, -8, -3, -6); printf("The biggest number is %d\n", result); return 0;}
详细解释开始咧。。。。。。
va_list arg; 转到定义:typedef char* va_list;重命名char* 为va_list。此处va_list就相当于 char*了,可以定义指针。
va_arg(arg, int);转到定义:#define va_arg __crt_va_arg,__crt_va_arg。
转到定义: #define __crt_va_arg(ap, t) ((t)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) 。
ap表示可变参数指针,而t表示数据类型。右边语句_INTSIZEOF(t)是什么意思呢?
继续查看 #define _INTSIZEOF(n) ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))。这又是什么意思呢?
别急,一步一步来,从右向左看。
(sizeof(int) - 1),There is no doubt that result is three。不装13了,该表达式结果是3,二进制位为0000 0000 0000 0000 0000 0000 0000 0011。加取反操作~结果是1111 1111 1111 1111 1111 1111 1111 1100 。 当参数t为char时,’&’前面的表达式结果取最小值4,二进制结果是0000 0000 0000 0000 0000 0000 0000 0100。因此,两边表达式运算结果是4。
那为什么要搞这么复杂的表达式呢?用sizeof关键字就好了咩。一般数据类型确实看上去求算有点复杂了,但是如果是结构体呢?结构体内有多种类型变量,如果继续使用简单的sizeof关键字求解的话,未免有些不太适合了。使用 ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1)),传入char,float,double等小于4字节的类型,都会返回4。相应的传入如果类型大小是,5,6,7的话,则返回8。即返回当前一组数中靠近4的倍数的值。当然5,6,7这几个值取的有点不太好,只是为了表达这个意思,勿深究。
说了那么多再来看看 (* (t*)( (ap += _INTSIZEOF(t) ) - _INTSIZEOF(t) ) )。注意括号套着哪个括号。该表达式先让指针ap加上4字节的大小,再把减去4字节大小处所对应的值返回。用t强制类型转换,再解引用。注意此处t是传入参数的数据类型。
最后谈谈va_end(arg);转到定义:#define va_end __crt_va_end,继续转到定义:#define __crt_va_end(ap) ((void)(ap = (va_list)0)),由此看出,该语句把整型0强制转换为字符0,然后传给指针ap,由此可知将ap清空。
- 可变参数源码的剖析和自己的理解
- 可变参数列表码的剖析和自己的理解
- 将可变参数列表源码的剖析和你自己的理解写一篇【漂亮】的博客。
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数列表源码的剖析
- 可变参数va_list的理解和使用
- 可变参数列表的源代码剖析
- c/c++中可变参数的理解和运用
- 帮助理解可变参数的应用【转贴】
- C语言可变参数设计的理解
- 关于c++可变参数的理解
- java可变参数概念的理解
- 关于Python可变参数的理解
- Shell中TMOUT变量的一个小应用
- 《守护树木》游戏策划
- python基础笔记3
- How To Install WordPress with nginx on Ubuntu 14.04
- TCP/IP详解卷1:协议(五)【ICMP:Internet控制报文协议,Ping程序】
- 可变参数源码的剖析和自己的理解
- babel的安装
- linux下 C++如何实现多线程
- Maven构建Hadoop工程
- SCU-4438 Censor(字符串HASH)
- shell处理文件,和lua计算求和
- c# 将数组或集合 转换成以逗号分隔的字符串
- MySql数据库无法插入中文?
- C++ P2P通信