这几个函数和变量是针对可变参数函数的,什么是可变参数函数呢,最经典的莫过于printf和scanf,这两个函数的声明如下:

 int printf(const char *format, ...);

 int scanf(const char *format, ...);

  这两个函数声明中省略号(...)表示的就是任意个数的参数,可变参数函数就是输入的参数的个数是可变的,那么这个具体是怎么实现的呢?

  要了解这个是怎么实现,首先我们就要先理解一点,参数是如何传递给函数的。众所周知,函数的数据是存放于栈中的,那么给一个函数传递传递参数的过程就是将函数的参数从右向左逐次压栈,例如:

  func(int i, char c, doube d)

  这个函数传递参数的过程就是将d,c,i逐次压到函数的栈中,由于栈是从高地址向低地址扩展的,所以d的地址最高,i的地址最低。

  理解了函数传递参数的过程,再来说一下va_list的原理,通常,可变参数的代码是这么写的:

 void func(char *fmt, ...)
{
va_list ap; va_start(ap, fmt);
va_arg(ap, int);
va_end(va);
}

  这里ap其实就是一个指针,指向了参数的地址。

  va_start()所做的就是让ap指向函数的最后一个确定的参数(声明程序中是fmt)的下一个参数的地址。

  va_arg()所做的就是根据ap指向的地址,和第二个参数所确定的类型,将这个参数的中的数据提取出来,作为返回值,同时让ap指向下一个参数。

  va_end()所做的就是让ap这个指针指向0。

  关于这三个参数实现的宏可以参看下面的实现:

 // 使ap指向第一个可变参数的地址
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) // 使ap指向下一个可变参数,同时将目前ap所指向的参数提取出来并返回
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) // 销毁ap
#define va_end(ap) ( ap = (va_list)0 )

参考文章:

1. 详解 C语言可变参数 va_list和_vsnprintf及printf实现

对C语言中va_list,va_start,va_arg和va_end的一点理解的更多相关文章

  1. va_list/va_start/va_arg/va_end深入分析【转】

    转自:http://www.cnblogs.com/justinzhang/archive/2011/09/29/2195969.html va_list/va_start/va_arg/va_end ...

  2. C++省略参数(va_list va_start va_arg va_end)的简单应用

    原文参考自:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html #include <iostream> #in ...

  3. va_list/va_start/va_arg/va_end深入分析

    http://www.cnblogs.com/justinzhang/archive/2011/09/29/2195969.html

  4. 深入C语言可变参数(va_arg,va_list,va_start,va_end,_INTSIZEOF)

    一.什么是可变参数 在C语言编程中有时会遇到一些参数个数可变的函数,例如printf(),scanf()函数,其函数原型为: int printf(const char* format,…),int ...

  5. va_list 、va_start、 va_arg、 va_end 使用说明【转】

    转自:https://blog.csdn.net/f110300641/article/details/83822290 在ANSI C中,这些宏的定义位于stdarg.h中: typedef cha ...

  6. va_start、va_arg、va_end、va_copy 可变参函数

    1.应用与原理         在C语言中,有时我们无法给出一个函数参数的列表,比如: int printf(const char *format, ...); int fprintf(FILE *s ...

  7. 深度探索va_start、va_arg、va_end

    采用C语言编程的时候,函数中形式参数的数目通常是确定的,在调用时要依次给出与形式参数对应的所有实际参数.但在某些情况下希望函数的参数个数可以根据需要确定.典型的例子有大家熟悉的函数printf().s ...

  8. va_start,va_arg,va_end的使用

    一.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表. void fun(...); void fun(parm_list,...); #include <stdi ...

  9. va_list arg_list va_start(arg_list, format) va_end( arg_list ) 原理的理解

    void log( int log_level, const char* file_name, int line_num, const char* format, ... ) { .......... ...

随机推荐

  1. 设置oracle_home

    set ORACLE_HOME=F:\app\rh\product\11.2.0\dbhome_1

  2. 101、使用ContentProvider在应用间传递数据

    [ContentWriter] package com.jikexueyuan.contentwriter; import android.content.ContentProvider; impor ...

  3. 查看django里所有的url

    >>> from django.core.urlresolvers import get_resolver >>> get_resolver(None).rever ...

  4. inno setup脚本,涵盖了自定义安装界面,调用dll等等应用

    ; Script generated by the Inno Setup 脚本向导. ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETU ...

  5. C Primer Plus(第五版)2

    在本章中你将学习下列内容------------------------------------------------------------------1.运算符:= 2.函数:main(),pr ...

  6. HDU 3068 [最长回文子串]

    #include<iostream> #include<string> #include<string.h> #include<algorithm> # ...

  7. mac下配置eclipse的hadoop环境

    下载eclipse-jee-mars-1-macosx-cocoa-x86_64.tar 右键显示包内容,将hadoop-eclipse-plugin-2.6.0.jar拷入到刚显示的包的plugin ...

  8. Temporary Segments: What Happens When a Sort Occurs (文档 ID 102339.1)

    APPLIES TO: Oracle Database - Enterprise Edition - Version 8.1.7.4 to 11.2.0.1 [Release 8.1.7 to 11. ...

  9. 【转】SQL Server 2008下载 (附注册码)

    SQL Server 2008 中文试用版下载地址:http://sqlserver.dlservice.microsoft.com/dl/download/B/8/0/B808AF59-7619-4 ...

  10. 【转】WEB测试到移动测试的转换

    移动互联网的发展毋庸置疑是必然的趋势,我们曾经传统WEB互联网测试的同学,也必然走上移动测试的道路,移动测试与pc测试到底需要怎样的思维转变才能更快的进入移动节奏呢?对比下WEB与移动的测试不同点: ...