热门标签 | 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了。

举报/反馈



推荐阅读
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
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社区 版权所有