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

举报/反馈



推荐阅读
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本文介绍如何使用 Python 将一个字符串按照指定的行和元素分隔符进行两次拆分,最终将字符串转换为矩阵形式。通过两种不同的方法实现这一功能:一种是使用循环与 split() 方法,另一种是利用列表推导式。 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • 本文详细介绍了 GWT 中 PopupPanel 类的 onKeyDownPreview 方法,提供了多个代码示例及应用场景,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 导航栏样式练习:项目实例解析
    本文详细介绍了如何创建一个具有动态效果的导航栏,包括HTML、CSS和JavaScript代码的实现,并附有详细的说明和效果图。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • CMake跨平台开发实践
    本文介绍如何使用CMake支持不同平台的代码编译。通过一个简单的示例,我们将展示如何编写CMakeLists.txt以适应Linux和Windows平台,并实现跨平台的函数调用。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用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社区 版权所有