C++可變參數的另一種實現

來源:互聯網
上載者:User

大家熟知的C庫函數printf函數就是一個可變參數函數,它是怎麼實現的呢?不過他實現是有條件的,必須函數參數的入棧順序為從右向左的順序,也即函數的形參,在函數調用之前,必須是最右邊的參數先入棧,並且參數都必須通過棧傳遞,以1個例子說明,如函數func(arg1, arg2,arg3),那麼函數的堆棧應是:

                              

ebp是幀指標寄存器,一般用來存取堆棧,有了堆棧結構,下面我們看看C可變參數的具體實現原理:

#include <stdio.h>enum {ptChar,ptInt,ptFloat,ptDouble,};void printSum(unsigned long paramFormat, ...){/*高16位為可變參數類型,低16位為可變參數個數*/int paramType = (paramFormat >> 16);int paramNum = paramFormat & 0xffff;/*¶mFormat = ebp + 8,第一個參數的地址*/unsigned long *pArg = ¶mFormat;/*ebp + 0x0c, 第二個參數地址*/pArg++;switch(paramType){case ptChar:{int sum = 0;for (int i = 0; i < paramNum; i++){char *pValue = (char *)pArg;sum += *pValue;pArg++;}printf("%d\n", sum);}break;case ptInt:{int sum = 0;for (int i = 0; i < paramNum; i++){int *pValue = (int *)pArg;sum += *pValue;pArg++;}printf("%d\n", sum);}break;case ptFloat:{float sum = 0;/**/pArg++;/*浮點參數,堆棧佔8個位元組,所以指標位移為8*/for (int i = 0; i < paramNum; i++){float *pValue = (float *)pArg;sum += *pValue;pArg++;pArg++;}printf("%f\n", sum);}break;case ptDouble:{double sum = 0;/*雙精確度浮點參數,堆棧佔8個位元組,所以指標位移為8*/for (int i = 0; i < paramNum; i++){double *pValue = (double *)pArg;sum += *pValue;pArg++;pArg++;}printf("%f\n", sum);}break;default:printf("unknowned type!\n");break;}}void main(){unsigned long paramFormat = 3;char a = 1, b = 2, c = 3;printSum(paramFormat, a, b, c);paramFormat = ptInt << 16;paramFormat += 3;int ia = 1, ib = 2, ic = 3;printSum(paramFormat, ia, ib, ic);paramFormat = ptFloat << 16;paramFormat += 3;float fa = 1, fb = 2, fc = 3;printSum(paramFormat, fa, fb, fc);paramFormat = ptDouble << 16;paramFormat += 3;double da = 1, db = 2, dc = 3;printSum(paramFormat, da, db, dc);}

上面這種方法對函數參數的入棧順序有限制,必須從右向左入棧,這就是為什麼pascal調用方式不能實現printf的原因,並且函數形參都要通過棧來傳遞,這對有些編譯器為了最佳化處理,函數參數通過寄存器來傳遞,從而不滿足要求。鑒於次,本文採用C++的預設形參實現可變參數的方法,沒有上面的這些限制,下面是實現代碼:

#include <stdio.h>enum {ptChar,ptInt,ptFloat,ptDouble,};void printSum(unsigned long paramType,  void *arg1 = NULL,  void *arg2 = NULL,  void *arg3 = NULL,  void *arg4 = NULL,  void *arg5 = NULL,  void *arg6 = NULL,  void *arg7 = NULL,  void *arg8 = NULL,  void *arg9 = NULL,  void *arg10 = NULL){void *arg[10] = {arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,};switch(paramType){case ptChar:{int sum = 0;for (int i = 0; i < 10; i++){if (arg[i] != NULL){char *pValue = (char *)arg[i];sum += *pValue;}elsebreak;}printf("%d\n", sum);}break;case ptInt:{int sum = 0;for (int i = 0; i < 10; i++){if (arg[i] != NULL){int *pValue = (int *)arg[i];sum += *pValue;}elsebreak;}printf("%d\n", sum);}break;case ptFloat:{float sum = 0;for (int i = 0; i < 10; i++){if (arg[i] != NULL){float *pValue = (float *)arg[i];sum += *pValue;}elsebreak;}printf("%f\n", sum);}break;case ptDouble:{double sum = 0;for (int i = 0; i < 10; i++){if (arg[i] != NULL){double *pValue = (double *)arg[i];sum += *pValue;}elsebreak;}printf("%f\n", sum);}break;default:printf("unknowned type!\n");break;}}void main(){unsigned long paramType = ptChar;char a = 1, b = 2, c = 3;printSum(paramType, &a, &b, &c);paramType = ptInt;int ia = 1, ib = 2, ic = 3;printSum(paramType, &ia, &ib, &ic);paramType = ptFloat;float fa = 1, fb = 2, fc = 3;printSum(paramType, &fa, &fb, &fc);paramType = ptDouble;double da = 1, db = 2, dc = 3;printSum(paramType, &da, &db, &dc);}

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.