日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

va_list/va_start/va_arg/va_end深入分析

發(fā)布時間:2024/2/28 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 va_list/va_start/va_arg/va_end深入分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

va_list/va_start/va_arg/va_end這幾個宏,都是用于函數(shù)的可變參數(shù)的。

我們來看看在vs2008中,它們是怎么定義的:

1: ///stdarg.h 2: #define va_start _crt_va_start 3: #define va_arg _crt_va_arg 4: #define va_end _crt_va_end 5: 6: ///vadefs.h 7: #define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) ) 8: typedef char * va_list; 9: #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) 10: #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) 11: #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 12: #define _crt_va_end(ap) ( ap = (va_list)0 ) ? 再看看各個宏的功能是什么?
  • va_list用于聲明一個變量,我們知道函數(shù)的可變參數(shù)列表其實就是一個字符串,所以va_list才被聲明為字符型指針,這個類型用于聲明一個指向參數(shù)列表的字符型指針變量,例如:va_list ap;//ap:arguement pointer
  • va_start(ap,v),它的第一個參數(shù)是指向可變參數(shù)字符串的變量,第二個參數(shù)是可變參數(shù)函數(shù)的第一個參數(shù),通常用于指定可變參數(shù)列表中參數(shù)的個數(shù)。
  • va_arg(ap,t),它的第一個參數(shù)指向可變參數(shù)字符串的變量,第二個參數(shù)是可變參數(shù)的類型。
  • va_end(ap) 用于將存放可變參數(shù)字符串的變量清空(賦值為NULL).

我們看一段具有可變參數(shù)列表的函數(shù)來求數(shù)組和的代碼:

1: /* 2: * 3: *功能: 宏va_arg()用于給函數(shù)傳遞可變長度的參數(shù)列表。 4: *首先,必須調(diào)用va_start() 傳遞有效的參數(shù)列表va_list和函數(shù)強制的第一個參數(shù)。第一個參數(shù)代表將要傳遞的參數(shù)的個數(shù)。 5: *其次,調(diào)用va_arg()傳遞參數(shù)列表va_list 和將被返回的參數(shù)的類型。va_arg()的返回值是當(dāng)前的參數(shù)。 6: *再次,對所有的參數(shù)重復(fù)調(diào)用va_arg() 7: *最后,調(diào)用va_end()傳遞va_list對完成后的清除是必須的。 8: * 9: *時間:2011年8月17日22:34:04 10: *作者:張超 11: *Email:uestczhangchao@gmail.com 12: * 13: */ 14: ? 15: ? 16: #include "X:\編程練習(xí)\C-C++\global.h" 17: ? 18: #if va_arg==stdon 19: #include <stdio.h> 20: #include <stdarg.h> 21: #include <stdlib.h> 22: ? 23: //第一個參數(shù)指定了參數(shù)的個數(shù) 24: int sum(int number,...) 25: { 26: va_list vaptr; 27: int i; 28: int sum = 0; 29: va_start(vaptr,number); 30: for(i=0; i<number;i++) 31: { 32: sum += va_arg(vaptr,int); 33: } 34: va_end(vaptr); 35: return sum; 36: } 37: ? 38: ? 39: int main() 40: { 41: printf("%d\n",sum(4,4,3,2,1)); 42: system("pause"); 43: return 0; 44: } 45: ? 46: #endif

?

  • va_start的功能是要把,ap指針指向可變參數(shù)的第一個參數(shù)位置處,

??? #define?_crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

?? 先取第一個參數(shù)的地址,在sum函數(shù)中就是取number的地址并且將其轉(zhuǎn)化為char *的(因為char *的指針進行加減運算后,偏移的字節(jié)數(shù)才與加的數(shù)字相同, 如果為int *p,那么p+1實際上將p移動了4個字節(jié)),然后加上4(__INITSIZEOF(number)=(4+3)&~3),這樣就將ap指向了可變參數(shù)字符串的第一個參數(shù)。

?

? #define?_INTSIZEOF(n) ( (sizeof(n) +?sizeof(int) - 1) & ~(sizeof(int) - 1) )

?

  • 以int所占的字節(jié)為標(biāo)準(zhǔn)進行對其操作。
  • 如果int占四字節(jié),則以四字節(jié)對齊為標(biāo)準(zhǔn)讀取數(shù)據(jù)。


????

  • va_arg是要從ap中取下一個參數(shù)。

?

?????? #define?_crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

?

對于這個宏,哥糾結(jié)了很久,最后終于搞清楚了,究其原因就是自己C語言功底不扎實,具體表現(xiàn)在沒有搞清楚賦值表達式的值是怎么運作的。 我們看這個宏,首先是ap = ap + __INTSIZEOF(t)。注意到,此時ap已經(jīng)被改變了,它已經(jīng)指向了下一個參數(shù),我們令x=ap + __INTSIZEOF(t); 那么括號內(nèi)就變成了(x – __INTSIZEOF(t)),但是這里沒有賦值運算符所以ap的值沒有發(fā)生變化,此時ap仍然指向的是當(dāng)前參數(shù)的下一個參數(shù)的位置, 也就是說ap指向的位置比當(dāng)前正在處理的位置超前了一個位置。 其實寫成下面的形式就簡單明了了:

??? #define?? va_arg(ap,t)?? (*(t?? *)((ap?? +=?? _INTSIZEOF(t)),???ap?? -?? _INTSIZEOF(t))?? )

? 分析:為什么要將ap指向當(dāng)前處理參數(shù)的下一個參數(shù)了? 經(jīng)過上面的分析,我們知道va_start(ap,v)已經(jīng)將ap指向了可變參數(shù)列表的第一個參數(shù)了,以后我們每一步操作都需要將ap移動到下一個 參數(shù)的位置,由于我們每次使用可變參數(shù)的順序是:va_start(ap,v)—>va_arg(ap,t);這樣我們在第一次去參數(shù)的時候,其實ap已經(jīng)指向了 第二個參數(shù)開始的位置,所以我們用表達式的方式獲得一個指向第一個參數(shù)的臨時指針,這樣我們就可以采用這種一致的方式來處理可變參數(shù)列表。 (感覺沒表達的十分清楚,希望各位朋友糾正~~~~~~)。 下圖是我的例子程序中去參數(shù)的情況(時間倉促,畫得很丑,請原諒): ? ?
  • va_end(ap)? 將聲明的ap指針置為空,因為指針使用后最后設(shè)置為空。
? 參考資料:
  • http://topic.csdn.net/u/20110830/15/a3630fc4-3c5f-4a1e-bbee-949ba7b4cbe0.html
  • http://topic.csdn.net/u/20070120/12/e8b7363b-6404-4d91-9307-01e5ed996f3d.html
  • 總結(jié)

    以上是生活随笔為你收集整理的va_list/va_start/va_arg/va_end深入分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。