C语言有个很强大的功能,依靠它,实现了printf等这类有着变长参数列表的函数或者宏。它就是在<stdarg.h>里的变长参数。

内容:

va_list   :它是一个适合保存va_start、va_arg和va_end所需要的信息的类型。
va_start :void va_start(va_list ap, parmN); 要在访问所有未命名的参数之前调用宏va_start,宏va_start对ap进行初始化,以便va_arg和va_end使用。
va_arg :type va_arg(va_list, type); 它展开是一个表达式,这个表达式的类型和值跟调用的下一个参数的相同。参数ap应该和va_start初始化的va_list ap相同。
va_end :如果没有执行va_start,或者在返回之前没有调用va_end,那么这种行为未定义。

实现:

还要用到我们在<stddef.h>中提到的<yvals.h>,它里面有两个宏:_AUPBND和_ADNBND

   #define _AUPBND (sizeof (acpi_native_int) - 1) //acpi_native_int 为4字节(32位)(根据机子字数而定)
#define _ADNBND (sizeof (acpi_native_int) - 1)
typedef char* va_list; // 因此,va_list实际上表示的是char*
#define va_start(ap, A) (void)((ap) = (char*)&(A) + _Bnd(A, _AUPBND))
#define va_arg(ap, T) (*(T*) (((ap) += _Bnd(T, _AUPBND)) - _Bnd(T, _ADNBND)))
#define va_end(ap) (void)0 #define _Bnd(X, bnd) (sizeof (X) + (bnd) &~(bnd) )

在实现里我们看到,va_list其实是char*类型,va_start将ap移动到参数列表的首地址,为va_arg的实现做准备,va_end啥都没干。

而va_arg是技巧性最强的一个。首先通过增加va_list对象的内容来使它跳向下一个参数空间的起始位置,然后然退回来指向当前参数的起始位置,然后通过强制类型住哪换把这个指针转换为指定类型的指针,最后解引用获得这个指针以访问存储在数据对象中的值。

在va_start和va_arg里,都用到了一个_Bnd(T, _AUPBND)或_Bnd(T, _ADNBND),由_AUPBND和_ADNBND的宏定义我们知道,它们总是等于在指定的机器中int类型的字节数减1。

事实上, _Bnd宏做的事情就是字节对齐,C语言函数入栈都是字节对齐的,都是所在机器上int类型字节的整数倍进行压栈,这样做可以是内存高效的访问。

sizeof(X)先计算出X类型的大小(假设为s),(bnd) & ~(bnd) 其实bnd就是_AUPBND和_ADNBND(我们假设它们都为3),先将X的大小加3,加了3就会清掉s的二进制数的最低两位,做个假设,假设s为7:00000111,然后加3:00000011,就变为00001010,最后&3的反:(11111100),最后_Bnd计算的结果就是00001000,为8,是int类型大小的整数倍,实现了字节对齐。

《C标准库》——之<stdarg.h>的更多相关文章

  1. 彻底弄清c标准库中string.h里的常用函数用法

    在我们平常写的c/c++程序,一些算法题中,我们常常会用到c标准库中string.h文件中的函数,这些函数主要用于处理内存,字符串相关操作,是很有用的工具函数.而且有些时候,在笔试或面试中也会出现让你 ...

  2. 走进C标准库(8)——"string.h"中函数的实现相关字符串操作函数

    我的strcat: char *strcat(char *dest,char *src) { char * reval = dest; while(*dest) dest++; while(*src) ...

  3. 走进C标准库(3)——"stdio.h"中的getc和ungetc

    接前文. 再来看看getc和ungetc的实现.在看这两个函数的实现之前,我们先来想一想这两个函数分别需要做的工作. int getc(FILE *stream) 说明:函数getc从stream指向 ...

  4. 走进C标准库(2)——"stdio.h"中的fopen函数

    其他的库文件看起来没有什么实现层面的知识可以探究的,所以,直接来看stdio.h. 1.茶余饭后的杂谈,有趣的历史 在过去的几十年中,独立于设备的输入输出模型得到了飞速的发展,标准C从这个改善的模型中 ...

  5. 走进C标准库(1)——assert.h,ctype.h

    默默觉得原来的阅读笔记的名字太土了,改了个名字,叫做走进C标准库. 自己就是菜鸟一只,第一次具体看C标准库,文章参杂了对<the standard C library>的阅读和对源码的一些 ...

  6. C 非标准库(conio.h)

    所谓的 C 标准库(C standard library),是指在 ISO C 或者 POSIX 标准中定义的: POSIX is a superset(超集) of the standard C l ...

  7. 走进C标准库(4)——"stdio.h"中的putc

    花了点时间把园子弄得好看了点,现在继续. 函数名: putc 功  能: 输出一字符到指定流中 用  法: int putc(int ch, FILE *stream); #define _putc_ ...

  8. 走进C标准库(5)——"stdio.h"中的其他部分函数

    函数介绍来自:http://ganquan.info/standard-c/ 函数名: freopen 功  能: 替换一个流 用  法: FILE *freopen(char *filename, ...

  9. 走进C标准库(6)——"string.h"中函数的实现memchr

    我写的memchr: void *memchr(const void *buf, char ch, unsigned count){ unsigned ; while(*(buf++) != ch & ...

  10. 走进C标准库(7)——"string.h"中函数的实现memcmp,memcpy,memmove,memset

    我的memcmp: int memcmp(void *buf1, void *buf2, unsigned int count){ int reval; while(count && ...

随机推荐

  1. 反质数(Antiprimes)

    转载http://www.cnblogs.com/tiankonguse/archive/2012/07/29/2613877.html 问题描述: 对于任何正整数x,起约数的个数记做g(x).例如g ...

  2. mac 连接mysql提示 Warning: mysqli::real_connect(): (HY000/2002): No such file or directory

    mac 连接mysql的时候提示 Warning: mysqli::real_connect(): (HY000/2002): No such file or directory [说明1]MAC下M ...

  3. (DFS)hdoj1241-Oil Deposit

    #include<cstdio> ][]; ][]={{,},{,-},{,},{-,},{,},{,-},{-,},{-,-}},cnt; void dfs(int x,int y) { ...

  4. 图书馆管理系统SRS

    1.任务概述 1.1目标 主要提供图书信息和读者基本信息的维护以及借阅等功能.本系统是提高图书管理工作的效率,减少相关人员的工作量,使学校的图书管理工作真正做到科学.合理的规划,系统.高效的实施. 1 ...

  5. 交互式报表和工作报表控件Stimulsoft Reports.Fx for Java

    Stimulsoft Reports.Fx for Java是一款Java平台下的报表工具控件,可以为您的应用程序添加交互式报表和工作报表.Java技术可以用于不同的平台.不同的操作系统和不同的硬件, ...

  6. android listview getviewtypecount和getItemViewType

    package newdemo.jeno.listviewdemo; import android.app.Activity;import android.os.Bundle;import andro ...

  7. RPI学习--WebCam_mplayer

    1,安装mplayer $ sudo apt-get install mplayer 2,运行 $ sudo mplayer tv:// 有时会秀逗,绿屏,多试几下就好了,情况未知

  8. ssh原理

     客户端向服务器端发出连接请求 服务器端向客户端发出自己的公钥 客户端使用服务器端的公钥加密通讯密钥然后发给服务器端 如果通讯过程被截获,由于窃听者即使获知公钥和经过公钥加密的内容,但不拥有私 ...

  9. SharePoint开发 - 自定义导航菜单(二)母版页的菜单应用

    博客地址 http://blog.csdn.net/foxdave 接上篇点击打开链接 本篇叙述在母版页中应用之前的配置信息生成菜单,主要涉及到母版页的自定义,并应用了第三方控件库DevExpress ...

  10. 【iOS开发】企业版证书($299)In-House方式发布指南 (转)

    一.明确几个概念 1.企业版IDP:即iOS Development Enterprise Program.注意是$299/Year那种,并不是$99/Year的那种. 2.In House:是只企业 ...