程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C語言中va(可變函數參數) 的另一種用法與危險事項

C語言中va(可變函數參數) 的另一種用法與危險事項

編輯:關於C

C語言中的可變參數va(va_arg) 大家應該比較熟悉了,主要是用來解決函數參數類型與個數不確定的問題,基本用法與詳細請移步這裡 /kf/201202/119885.html
通常的用法是把va_arg放在等號右邊,提取其值來使用:
[cpp]
func( Type para1, Type para2, Type para3, ... ) 

    /****** Step 1 ******/ 
    va_list ap; 
    va_start( ap, para3 ); //一定要“...”之前的那個參數 
     
    /****** Step 2 ******/ 
    //此時ap指向第一個可變參數 
    //調用va_arg取得裡面的值 
    Type xx = va_arg( ap, Type );  
     
    //Type一定要相同,如: 
    //char *p = va_arg( ap, char *); 
    //int i = va_arg( ap, int ); 
 
    //如果有多個參數繼續調用va_arg 
 
    /****** Step 3 ******/ 
    va_end(ap); //For robust! 

這裡介紹va的另一種用法:把va_arg()當左值使用:
[cpp]
<pre class="cpp" name="code">//函數定義: 
PassInto(ID, ...)  

 
    va_list valist; 
 
    va_start(valist, ID); 
 
    *(uint32_t*)va_arg(valist, uint32_t*) = 10; 
    va_end(valist); 

//調用: 
uint32_t value = 0; 
PassInto(id, &value); 
 
printf("%d", value); 

得到結果是value被賦值為10。
可以看到,這裡va_arg被放到了等號左邊,好像很奇怪的用法,實際上分析一下,同放在右邊原理都是一樣的。因為不論va的原理如何(見上面的鏈接),
C語言的函數歸根到底還是值傳遞的,在第一種通常的用法中,va值被取出來後賦值給其它變量,在第二種用法中,&value被當作va傳了進去,
它的值其實就是一個指向value的指針,所以 va_arg(valist, uint32_t*) 取出的是一個uint32_t的指針,*(uint32_t*)va_arg(valist, uint32_t*) =10 即把這個指針強制類型轉換為(uint32_t*)並加*號間接引用,
這樣實際得到了變量value,現在把它賦值為10,就等價於
[cpp]
value = 10; 
這樣就完成了我們的全部操作,實現了對任意類型和個數的參數進行賦值。
這個方式超級靈活,但是注意不要進行下面的危險操作:
[cpp]
uint16_t value = 0;   //這裡有變化 
PassInto(id, &value); 
後果可能很嚴重。為什麼呢?因為參數類型不匹配,16位的參數被強迫當作32位來使用。我們的value同志此時只從系統那裡申請到了16bit的空間,而
[cpp]
*(uint32_t*)va_arg(valist, uint32_t*) =10  
把10塞到了從value開始的32位空間,那麼value之後的那16bit是哪裡呢?由誰在用?不得而知。
如果運氣好,沒有人在用,程序無事,如果數據在用,那麼數據會變化,系統在用,系統也跑偏。
反正我用的時候它沒和我客氣,系統直接崩潰了。

摘自 herbert的知識庫

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