微博:http://weibo.com/u/2203007022           




 (1)      C语言可变參数

我们能够从C语言的printf得出可变參数的作用。printf函数的原型例如以下:

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

通过使用可变个数參数,就是传入的參数个数是可变的,如printf须要依据format实參传入多个实參。

(2)      C语言可变參数的使用

以下一个函数myprintf是自己实现的比較简单的printf函数。不完整可是能够说明可变參数的使用方法。

/*
* Author: guojun07
*/ #include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h> void myprintf(char *format, ...) {
va_list ap;
int pos = 0;
int int_val = 0;
float f_val;
char buf[64];
memset(buf, 0, 64);
// 得到全部的參数放到下一个list中ap中
va_start(ap, format);
while (format[pos] != '\0') {
// 推断'%'。表示要得到下一个參数
if (format[pos] == '%') {
pos ++;
switch(format[pos]) {
case 'd':
case 'u':
// 得到ap中的下一个參数
int_val = va_arg(ap, int);
sprintf(buf, "%d", int_val);
// 将数据写到标准输出
write(STDOUT_FILENO, buf, strlen(buf));
memset(buf, 0, 64);
pos ++;
break;
case 'f':
// 得到ap中的下一个參数
f_val = (float)va_arg(ap, double);
sprintf(buf, "%f", f_val);
// 将数据写到标准输出
write(STDOUT_FILENO, buf, strlen(buf));
memset(buf, 0, 64);
pos ++;
break;
default:
break;
}
} else {
write(STDOUT_FILENO, &(format[pos]), 1);
pos ++;
}
}
} int main(void){
myprintf("this is a testing, i = %d, u = %u, f = %f\n", -1, 5, 0.2);
return 0;
}

程序的数据结果例如以下:

guojun8@guojun8-desktop:~/test/valist$ ./main
this is a testing, i = -1, u = 5, f = 0.200000

(3)      实现

以下介绍C语言可变长度參数的实现。事实上现与一个数据结构(va_list)和三个宏(va_start, va_end, va_arg)相关,从源代码中能够看到这些实现以下的来自linux内核源代码中的文件(include/acpi/platform/acenv.h)

#ifndef _VALIST
#define _VALIST
typedef char *va_list;
#endif        /* _VALIST */
 
/*
* Storage alignment properties
*/
#define  _AUPBND                (sizeof (acpi_native_int) - 1)
#define  _ADNBND                (sizeof (acpi_native_int) - 1)
 
/*
* Variable argument list macro definitions
*/
#define _bnd(X, bnd)            (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T)           (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap)              (void) 0
#define va_start(ap, A)         (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))

a)         va_list

从实现中能够看出va_list类型实际上就是一个指针。

b)        va_start

这个宏的作用是将T所指向的參数后面的内容放到ap中。当中_bnd (A,_AUPBND)是返回A的size并与系统的机器位数对齐。由于參数在栈中的地址一定是与系统的字长对齐的,当中acpi_native_int就表示机器字长。

c)         va_end

这个宏的作用就是返回0。

d)        va_arg

这个宏的作用是取得ap指向的当前的參数,并将ap指向參数列表中的下一个參数。

C语言可变长參数实现原理的更多相关文章

  1. C语言变长參数的认识以及宏实现

    1.认识 变长參数是C语言的特殊參数形式.比如例如以下函数声明: int printf(const char *format, ....); 如此的声明表明,printf函数除了第一个參数类型为con ...

  2. Java 变长參数Varargs

    Varargs (variable arguments)可变长參数是Java 1.5引入的特性. 方法的形參如print(String ... s),实參为随意数目的值. public class V ...

  3. java 变长參数使用原则

    1.java变长參数用...表示,如Print(String... args){  ... }; 2.假设一个调用既匹配一个固定參数方法.又匹配一个变长參数方法,则优先匹配固定參数的方法 3.假设一个 ...

  4. C++11 新特性之 变长參数模板

    template <typename ... ARGS> void fun(ARGS ... args) 首先明白几个概念 1,模板參数包(template parameter pack) ...

  5. C语言函数參数传递原理

    C语言中參数的传递方式一般存在两种方式:一种是通过栈的形式传递.还有一种是通过寄存器的方式传递的. 这次.我们仅仅是具体描写叙述一下第一种參数传递方式,第二种方式在这里不做具体介绍. 首先,我们看一下 ...

  6. linux kernel的cmdline參数解析原理分析

    利用工作之便,今天研究了kernel下cmdline參数解析过程.记录在此.与大家共享.转载请注明出处.谢谢. Kernel 版本:3.4.55 Kernel启动时会解析cmdline,然后依据这些參 ...

  7. [转]深度探索C语言函数可变长参数

    转自:http://www.cnblogs.com/chinazhangjie/archive/2012/08/18/2645475.html 一.基础部分 1.1 什么是可变长参数 可变长参数:顾名 ...

  8. object-c 不定參数的遍历和原理

    object-c接收随意类型的參数: /** * 接收String类型的多个參数 * @param firsParam 第一个參数 */ -(void)TestString:(NSString*)fi ...

  9. Effective JavaScript Item 22 使用arguments来创建接受可变參数列表的函数

    本系列作为Effective JavaScript的读书笔记. 在Item 21中,介绍了结合apply方法实现的可变參数列表函数average,它实际上仅仅声明了一个数组作为參数,可是利用apply ...

随机推荐

  1. Linux系列教程(十六)——Linux权限管理之ACL权限

    通过前面的两篇博客我们介绍了Linux系统的用户管理,Linux用户和用户组管理之相关配置文件 讲解了用户管理的相关配置文件,包括用户信息文件/etc/passwd,用户密码文件/etc/shadow ...

  2. 【开源】canvas图像裁剪、压缩、旋转

    前言 前段时间遇到了一个移动端对图像进行裁剪.压缩.旋转的需求. 考虑到已有各轮子的契合度都不高,于是自己重新造了一个轮子. 关于图像裁剪.压缩 在HTML5时代,canvas的功能已经非常强大了,可 ...

  3. [转载] Hive与HBase的联系与区别

    转载自http://blog.csdn.net/wangmuming/article/details/23954527和http://www.cnblogs.com/justinzhang/p/427 ...

  4. MarkdownPad2代码高亮插件兼容移动端样式

    如果不知道MarkdownPad2使用代码高亮插件可以查看前一篇文章<MarkdownPad2使用代码高亮插件> 先看移动端效果图: 移动端点击查看效果 或者手机扫如下二维码: 我们经常阅 ...

  5. Javaweb学习(一):tomcat服务器配置与启动

    目前所使用的集成开发环境为myeclipse10.7,tomcat版本为apache-tomcat-7.0.82,部分编写地方可能有所不同,但是工具不是最主要的,重要的是掌握的知识. tomcat在m ...

  6. Python案例分享

    1.过桥(爬金字塔): 1 i = 1 2 while i <= 9: 3 if i < 6: 4 j = 0 5 while j < i: 6 print('*',end=' ') ...

  7. Winform界面中实现通用工具栏按钮的事件处理

    在一个给客户做的项目中,界面要求修改增加通用工具栏按钮的事件处理,也就是在主界面中放置几个固定的功能操作按钮,打开不同的页面的时候,实现对应页面的功能处理,这种和我标准的界面处理方式有所不同,标准的列 ...

  8. 二维,多维数组排序array_multisort()函数的使用

    对于数组的排序,很很多方法:随便百度了一下 sort() - 以升序对数组排序 rsort() - 以降序对数组排序 asort() - 根据值,以升序对关联数组进行排序 ksort() - 根据键, ...

  9. 个人笔记之json实现模糊查询

    1:首先创建一个项目如:(说明:此项目是在eclipse创建的) 2.在创建相对应的包如: 3.创建写好相对应的配置文件如: applicationContext.xml具体内容如下: <?xm ...

  10. ShoneSharp语言(S#)的设计和使用介绍系列(1)— 开篇

    ShoneSharp语言(S#)的设计和使用介绍 系列(1)- 开篇 作者:Shone 声明:原创文章欢迎转载,但请注明出处,https://www.cnblogs.com/ShoneSharp. 一 ...