ANSI C——可變參數

來源:互聯網
上載者:User
文章目錄
  • 【原型】
  • 【描述】
  • 【使用方法】
  • 【實現分析】
  • 【例子分析】
【原型】

      type fun( type arg1, type arg2, ...

);

【描述】

       主要用在參數個數不確定的函數中,例如:printf函數。

【使用方法】

參考:glib/manual/Add.c

#include <stdarg.h><br />#include <stdio.h><br />int add_em_up (int count,...)<br />{<br /> va_list ap;<br /> int i, sum;<br /> va_start (ap, count);/* Initialize the argument list. */<br /> sum = 0;<br /> for (i = 0; i < count; i++)<br /> sum += va_arg (ap, int);/* Get the next argument value. */<br /> va_end (ap);/* Clean up. */<br /> return sum;<br />}<br />int main (void)<br />{<br /> /* This call prints 16. */<br /> printf ("%d/n", add_em_up (3, 5, 5, 6));<br /> /* This call prints 55. */<br /> printf ("%d/n", add_em_up (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));<br /> return 0;<br />}

運行結果:

 

16                               

55                               

【實現分析】

      如果要實現可變參數,關鍵是我們怎樣遍曆函數列表
,這就牽扯到函數的參數鏈表在棧中的存放順序問題:

      函數入棧的過程大致如下: (更詳細的內容參考這裡
)

  1. 函數的局部變數入棧;
  2. 其他被調函數資訊指標入棧;
  3. 函數返回地址入棧;
  4. 參數列表入棧,順序從右至左;

此時我們可以明確參數列表的存放順序,如下:

 

      所以我們必須要知道棧頂參數地址,即函數的第一個參數;

 

      主要依靠定義在stdarg.h中三個宏:

 

  • void va_start( va_list arg_ptr, prev_param );  /*給出第一個參數的地址*/
  • type va_arg( va_list arg_ptr, type );                /*從第二個參數開始取,每次返回一個*/
  • void va_end( va_list arg_ptr );                         /*標記已取完,其實什麼也不做*/

stdarg.h的實現和注釋如下:

#ifndef _STDARG_H<br />#define _STDARG_H<br />typedef char *va_list;<br />/*根據類型值做記憶體對齊*/<br />#define __va_rounded_size(TYPE) /<br /> (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))</p><p>/*根據第一參數LASTARG的地址,擷取第二參數地址*/<br />#define va_start(AP, LASTARG) (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))<br />/*已完成,無需做*/<br />#define va_end(AP)<br />/*根據TYPE,返回當前AP指向的參數值,AP指向下一個<br />這裡用到逗號運算式,先左後右,最右邊的是這個結果。<br />AP += __va_rounded_size (TYPE), 指向下一個參數;<br />(AP += __va_rounded_size (TYPE),返回上一個參數;<br />*/<br />#define va_arg(AP, TYPE) /<br />(AP += __va_rounded_size (TYPE), *((TYPE *) (AP - __va_rounded_size (TYPE))))<br />#endif /* _STDARG_H */

 

其實stdarg.h的實現會依據編譯器的不同有所差異,瞭解更多查看這裡

 

【例子分析】

這個例子我們可以修改一下glib/manual/Add.c 如下:add_ex.c

#include <stdarg.h><br />#include <stdio.h><br />int show_arg (int count,...)<br />{<br /> va_list ap;<br /> int i = 1;<br /> va_start (ap, count); /* 給出第一參數的地址 */<br /> printf("first arg address =%d/n",(unsigned int)ap-sizeof(count));<br /> for (i = 1; i <= count; i++)<br /> printf("%d = %d /t next_addre =%d/n",i,va_arg (ap, int),(unsigned int)ap); /*迴圈取下一個參數*/<br /> va_end (ap);/* 結束 */<br /> return 0;<br />}<br />int main (void)<br />{</p><p> /*我們把 count的值故意多設定一個,<br />這樣我們顯示第六個的值應該是函數的返回地址*/<br /> show_arg(10, 1, 2, 3, 4, 5);<br /> return 0;<br />}<br />

 

運行結果: GCC和vc的編譯結果有差異。

 

 

轉載請聲明來處:http://blog.csdn.net/oncoding/archive/2009/09/13/4549160.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.