C語言println函數


發現很多現代的語言中都有println這個函數,用起來很是方便,不用每次打印都要加上"\n",自己也實現了一個,方便平時調試的時候用。

 
 
 
         
  1. #include <stdarg.h>
  2. int println(const char *fmt, ...)
  3. {
  4. char printf_buf[1024];
  5. va_list args;
  6. int printed;
  7. va_start(args, fmt);
  8. printed = vsprintf(printf_buf, fmt, args);
  9. va_end(args);
  10. puts(printf_buf);
  11. return printed;
  12. }

這里用到了C語言的可變參函數,就順便談談C語言的可變參函數吧。所謂可變參函數即函數的參數可以是不定個數。上面我們已經看到了變參函數的定義方法,用形如int println(const char *fmt, ...)來定義可變參函數。

注意:上例中的第一個參數fmt是不可省略的,可變參函數至少需要一個普通的形參。


C語言之所以支持可變參函數,一個重要的原因是C調用規范中規定了C語言函數調用時,參數入棧的書序是從右往左,這意味着,棧頂的參數是第一個參數。這樣,被調用的函數,就不需要關心調用者會傳遞幾個參數進來,只要關心自己用到幾個參數既可以了。

例如這樣一個調用

查看函數的匯編代碼

可以看到,對println("%d %d", 10, 20, 30, 40);的調用確實是從右往左將參數壓入到棧中。


這里還有另外一個問題是:因為可變參函數,函數定義的時候並沒有定義形參原型,調用的時候怎么使用參數呢?為此,C語言定義了如下的宏:

 
 
 
         
  1. void va_start(va_list ap, last);//取第一個可變參數(如上述printf中的i)的指針給ap,last是函數聲明中的最后一個固定參數(比如printf函數原型中的*fromat);
  2. type va_arg(va_list ap, type);//返回當前ap指向的可變參數的值,然后ap指向下一個可變參數;type表示當前可變參數的類型(支持的類型位int和double);
  3. void va_end(va_list ap);//將ap置為NULL

其在頭文件中的定義如下:

 
 
 
         
  1. /*
  2. * define a macro to compute the size of a type, variable or expression,
  3. * rounded up to the nearest multiple of sizeof(int). This number is its
  4. * size as function argument (Intel architecture). Note that the macro
  5. * depends on sizeof(int) being a power of 2!
  6. */
  7. #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
  8. #define _VA_LIST char*
  9. typedef _VA_LIST va_list;
  10. #define va_dcl va_list va_alist;
  11. #define va_start(ap) ap = (va_list)&va_alist
  12. #define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
  13. #define va_end(ap) ap = (va_list)0

從上面的定義很容易可以看出,va_start使ap指向第一個可選參數。va_arg返回參數列表中的當前參數並使ap指向參數列表中的下一個參數。va_end則將ap置為空指針。
關於_INTSIZEOF做一點簡單的解釋:因為sizeof(int)2^n,因此它的位模式必然是1...000,因此該宏會






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM