C语言可变长参数实现原理

博客:存储系统研究

微博: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;
}

程序的数据结果如下:

[email protected]:~/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语言可变长参数实现原理,布布扣,bubuko.com

时间: 2024-12-23 09:14:52

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

C语言可变长参数 思考

1.我们为什么需要可变长参数 各种编程语言,如C.C++.java等都实现了可变长参数的函数.普通函数的参数个数是确定的,如果同一个函数可以接受不同数目的参数就需要适用到可变长度的参数.可变长度参数一个最典型的例子就是printf和scanf.以printf为例子,如可以有printf("Hello Word"),printf("Hello word%s","!"),printf("Hello word%s%d","

深度探索C语言函数可变长参数

通常我们使用的C函数的参数个数都是固定的,但也有不固定的.比如printf()与scanf().如何自己动手实现一个可变参数函数,这个还是有点技巧的. 我们最常用的就是定义一个宏,使用printf或者printk,如下 #define wwlogk(fmt, args...) printk(fmt, ## args) 现在我们自己动手实现一个可变参数的函数,后面分析原理.首先看一个例子: #include <stdio.h> #include <stdarg.h> int Sum(

C 可变长参数运用-----编写Lua的通用调用函数

1.C可变长参数 printf这个使用频繁的C语言函数的参数列表包含一个const char*的描述串,还有一个可变长参数(...) ,如下为printf的函数声明. int printf(const char * __restrict, ...) 在stdarg.h这个头文件中包含着对可变长参数进行操作的一些宏(x86平台为例): #define va_start(ap,v)( ap = (va_list)&v + _INTSIZEOF(v) ) #define va_arg(ap,t) ( 

可变长参数的函数的写法

c语言中的可变长参数的函数小例子: #include <stdio.h> #include <stdarg.h> #include <assert.h> static int pp; void func1() { static int pp1; printf("hello world\n"); } void tiny_printf(char *format, ...) { int i; va_list ap; va_start(ap, format)

Python——函数 8、可变长参数

可变长参数:可变长指的是实参的个数不固定按位置定义的可变长的实参:*按关键字定义的可变长的实参:** 一.按位置 def func(x,y,*args): print(x,y) print(args) func(1,2,3,4,5) # *处理按位置定义的多出的实参 # 然后赋值给*后的变量来保存成一个元组的形式 # args=(3,4,5) 1.等效 def func(x,y,*args): print(x,y) print(args) func(1,2,*(3,4,5)) #与func(1,

[C]va_list可变长参数的使用

一.概述 运用标准C的头文件stdarg.h提供的宏可以实现函数的自定义传参个数: 二.语法 1.va_list是一个可变长参数类型,在使用可变长参数的函数中可以定义1个或多个va_list类型参数,等待va_start初始化后使用: va_list parg_1; va_list parg_2; 2.va_start作用是给va_list类型变量绑定一个起始值 宏原型: void va_start(va_list ap, last); ap是va_list类型变量: last是函数的最后一个固

关于C中可变长参数

前言 可变长参数指函数的参数个数在调用时才能确定的函数参数.基本上各种语言都支持可变长参数,在特定情形下,可变长参数使用起来非常方便.c语言中函数可变长参数使用"..."来表示,同时可变长参数只能位于固定参数的后面,固定参数的个数至少为1.只要学习过c语言的,应该都知道printf函数,并且见识到了其强大的功能--事实上,迄今为止,我仍认为这是c函数库中最牛逼的函数之一. 一.一个简单的例子 #include <string>  #include <stdio>

Java中可变长参数的使用及注意事项

在Java5 中提供了变长参数(varargs),也就是在方法定义中可以使用个数不确定的参数,对于同一方法可以使用不同个数的参数调用,例如print("hello");print("hello","lisi");print("hello","张三", "alexia");下面介绍如何定义可变长参数 以及如何使用可变长参数. 1. 可变长参数的定义 使用...表示可变长参数,例如 prin

可变长参数(*,**)

可变长参数 python还支持可变长度的参数列表.可变长参数可以是元组或者字典. 1.元组 当参数以*开头时,表示变长参数将被视为一个元组,格式如下: def func(*t): 在func()函数中t被视为一个元组,使用t[index]获取每一个可变长参数. 例如: 1 def func1(*t): 2 print("可变长参数数量如下:") 3 print(len(t)) 4 print("依次为:") 5 for x in range(len(t)): 6 p