热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c语言va1是什么,c语言不定参数宏,va_start,va_arg的来历解释

关于INTSIZEOF宏是怎么来的已经解释过了,这里简要概述一下,宏定义如下:#define_INTSIZEOF(n)((sizeof(n

关于INTSIZEOF宏是怎么来的已经解释过了, 这里简要概述一下,宏定义如下:

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

当sizeof(n)<4时&#xff0c;宏的值就是4&#xff0c;当sizeof(n)>4时&#xff0c;宏的值就是4的倍数。

这里主要介绍两个宏va_start和va_arg两个宏&#xff0c;先说这个va_start。

宏定义如下&#xff1a;

#define va_start(ap,v) ( ap &#61; (va_list)&v &#43; _INTSIZEOF(v) )&#xff0c;这里的va_list的类型是

char *&#xff0c;v是输入的第一个参数。首先在理解这个宏的前提要理解函数的形参是如何存储&#xff0c;这里我们做个试验如下图所示

形参是存储在栈里面的&#xff0c;栈的高地址在上&#xff0c;低地址在下&#xff0c;那么由上图可以得到的是&#xff0c;x&#xff0c;y&#xff0c;z在栈中存储的结构从上到下依次为z&#xff0c;y&#xff0c;x。那么(va_list)&v的意思就是取第一个参数的地址并强制转化为char*类型。比如这里的x的地址为1638116(十进制表示的)被强制转化为char*&#xff0c;对于_INTSIZEOF(v)&#xff0c;若是这里的v也为x的话&#xff0c;那么这个宏的值为4。进而两者相加的值就是1638120。这里要说明的是地址的类型为char*的话&#xff0c;地址加1就相当于只是加1&#xff0c;比如这里的1638116 &#43; 4 &#61; 1638120&#xff1b;如果地址的类型是int *那么加1的意思就是地址&#43;1*4。为什么&#xff1f;&#xff1f;&#xff1f;是这样的&#xff1a;比如一个指针指向一个int的输入比如int a[10],那么每一个元素就占4个字节所以地址&#43;1中的1表示1*4&#xff0c;所谓的指针加几就是为了向前或者向后移动&#xff0c;那么移动多少字节就要取决于指针指向的变量的类型了&#xff0c;这样解释明白了吧&#xff01;&#xff01;&#xff01;很基础是吧&#xff0c;比如数组是char型的&#xff0c;那么加1就是地址纯粹的加1了&#xff0c;因为sizeof(char) &#61; 1的嘛。

好了&#xff0c;继续上面说的得到了地址1638116 &#43; 4 &#61; 1638120&#xff0c;那么这个1638120不正好就是y的地址值吗。所以这个宏的功能就是&#xff1a;输入第n个参数&#xff0c;输出的就是第n &#43; 1个参数的地址值。再来介绍va_arg宏&#xff0c;它的定义如下&#xff1a;

#define va_arg(ap,t) ( *(t *)((ap &#43;&#61; _INTSIZEOF(t)) - _INTSIZEOF(t)) )&#xff0c;这里的t输入的是变量的类型&#xff0c;比如int&#xff0c;char等等之类的。ap &#43;&#61; _INTSIZEOF(t)的意思让指针ap指向下一个参数的地址&#xff0c;在强调一遍高地址存的是函数越右边的形参值(因为形参是存在栈中的)&#xff0c;比如假设ap指向的是x的地址&#xff0c;要使得ap指向y&#xff0c;那么由于x是在低地址那么就要加上x的类型&#xff0c;比如这里的x类型为int&#xff0c;所以这个时候ap是指向y的了。再减去_INTSIZEOF(t)(注意此时ap还是指向的y)那么((ap &#43;&#61; _INTSIZEOF(t)) - _INTSIZEOF(t))整个地址值就还原到原来的地方&#xff0c;也就是再次指向了x&#xff0c;为什么又要回来&#xff0c;其实就是为了使得ap指向下一个地址&#xff0c;然后再次回到原来的地址&#xff0c;在经过强制转化(t *)&#xff0c;然后再取值*(t *)的符号“*”。

我们来捋一捋这个过程&#xff0c;假设函数只有x&#xff0c;y&#xff0c;z三个形参&#xff0c;一般先调用va_start使得ap指向了y&#xff0c;然后再调用va_arg&#xff0c;使得ap指向z&#xff0c;由于y的值没取出来进行计算&#xff0c;那么&#xff0c;就要把地址还原也就是上面再减去_INTSIZEOF(t)&#xff0c;在取出y的值。那么这里就有一个问题是x的值并没用到&#xff0c;别急看完下面的例子就明白怎么用x的值了。

我们来举一个例子来应用一下&#xff0c;我们要实现&#xff0c;不管输入多少个参数&#xff0c;使得函数形参从第二个参数开始起进行累加&#xff0c;如下图所示&#xff1a;

a938af32071a41880312d8de2c029da1.png

function函数形参x表示的是有多少个参数&#xff0c;因为在执行va_start的时候就直接使得ap的指针指向了下一个形参的位置&#xff0c;所以可以利用x的值来表示有多少个参数&#xff0c;比如这里有4个参数&#xff0c;分别为0,1,2,3,4&#xff0c;那么function的功能就是把这几个值相加也就是6了。

举报/反馈



推荐阅读
  • 2.2 组件间父子通信机制详解
    2.2 组件间父子通信机制详解 ... [详细]
  • 【妙】bug称它为数组越界的妙用
    1、聊一聊首先跟大家推荐一首非常温柔的歌曲,跑步的常听。本文主要把自己对C语言中柔性数组、零数组等等的理解分享给大家,并聊聊如何构建一种统一化的学习思想 ... [详细]
  • String字符串与字符数组#includeStringintmain(){char*strhello;字符串与字符数组的关系:字符串是 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 字符串学习时间:1.5W(“W”周,下同)知识点checkliststrlen()函数的返回值是什么类型的?字 ... [详细]
  • javascript分页类支持页码格式
    前端时间因为项目需要,要对一个产品下所有的附属图片进行分页显示,没考虑ajax一张张请求,所以干脆一次性全部把图片out,然 ... [详细]
  • 如何在Java中使用DButils类
    这期内容当中小编将会给大家带来有关如何在Java中使用DButils类,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。D ... [详细]
  • 在PHP中,为了更高效地打开和读取目录并列出其中的文件,可以使用一个自定义函数来返回查询目录下的文件和文件夹列表。该函数会将结果以数组形式返回,并明确区分每个条目是文件还是目录,从而提供更友好和实用的输出。此外,该函数还可以进一步扩展,支持递归查询子目录,以便更全面地获取目录结构信息。 ... [详细]
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • 本题主要考察二维数组的遍历和重塑。通过将二维数组降为一维,再根据新的行数和列数重新构建矩阵。 ... [详细]
  • 本文详细介绍了Java反射机制的基本概念、获取Class对象的方法、反射的主要功能及其在实际开发中的应用。通过具体示例,帮助读者更好地理解和使用Java反射。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 本文介绍了一种在ANSI C中动态分配二维数组的方法。通过创建指针数组并为每个指针分配连续空间,可以灵活地管理内存。文章还讨论了一些常见的错误和注意事项。 ... [详细]
author-avatar
小新
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有