程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C語言可變長參數實現原理

C語言可變長參數實現原理

編輯:關於C
 

(1) C語言可變參數

我們可以從C語言的printf得出可變參數的作用,printf函數的原型如下:
int printf ( const char * format, ... );
通過使用可變個數參數,就是傳入的參數個數是可變的,如printf需要根據format實參傳入多個實參。

(2) C語言可變參數的使用

下面一個函數myprintf是自己實現的比較簡單的printf函數,不完整但是可以說明可變參數的用法。
/*
 * Author: guojun07
 */

#include 
#include 
#include 
#include 

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] != '') {
    // 判斷'%',表示要得到下一個參數
    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
, -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指向參數列表中的下一個參數;

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved