欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
C,C++中使用可變參數(轉)
可變參數即表示參數個(gè)數可以變化,可多可少,也表示參數的類(lèi)型也可以變化,可以是int,double還可以是char*,類(lèi),結構體等等??勺儏凳菍?shí)現printf(),sprintf()等函數的關(guān)鍵之處,也可以用可變參數來(lái)對任意數量的數據進(jìn)行求和,求平均值帶來(lái)方便(不然就用數組或每種寫(xiě)個(gè)重載)。在C#中有專(zhuān)門(mén)的關(guān)鍵字parame,但在C,C++并沒(méi)有類(lèi)似的語(yǔ)法,不過(guò)幸好提供這方面的處理函數,本文將重點(diǎn)介紹如何使用這些函數。

 

第一步 可變參數表示

用三個(gè)點(diǎn)…來(lái)表示,查看printf()函數和scanf()函數的聲明:

int printf(const char *, ...);

int scanf(const char *, ...);

這三個(gè)點(diǎn)用在宏中就是變參宏(Variadic Macros),默認名稱(chēng)為_(kāi)_VA_ARGS__。如:

#define WriteLine(...) { printf(__VA_ARGS__); putchar('\n');}

再WriteLine("MoreWindows");

考慮下printf()的返回值是表示輸出的字節數。將上面宏改成:

#define WriteLine (...) printf(__VA_ARGS__) + (putchar('\n') != EOF ? 1: 0);

這樣就可以得到WriteLine宏的返回值了,它將返回輸出的字節數,包括最后的’\n’。如下例所示i和j都將輸出12。

       int i = WriteLine("MoreWindows");

       WriteLine("%d", i);

       int j = printf("%s\n", "MoreWindows");

       WriteLine("%d", j);

 

第二步 如何處理va_list類(lèi)型

函數內部對可變參數都用va_list及與它相關(guān)的三個(gè)宏來(lái)處理,這是實(shí)現變參參數的關(guān)鍵之處。

在<stdarg.h>中可以找到va_list的定義:

typedef char *  va_list;

再介紹與它關(guān)系密切的三個(gè)宏要介紹下:va_start(),va_end()和va_arg()。

同樣在<stdarg.h>中可以找到這三個(gè)宏的定義:

#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )

#define va_end(ap)      ( ap = (va_list)0 )

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

其中用到的_INTSIZEOF宏定義如下:

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

來(lái)分析這四個(gè)宏:

va_end(ap)這個(gè)最簡(jiǎn)單,就是將指針置成NULL。

va_start(ap,v)中ap = (va_list)&v + _INTSIZEOF(v)先是取v的地址,再加上_INTSIZEOF(v)。_INTSIZEOF(v)就有點(diǎn)小復雜了。( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )全是位操作,看起來(lái)有點(diǎn)麻煩,其實(shí)不然,非常簡(jiǎn)單的,就是取整到sizeof(int)。比如sizeof(int)為4,1,2,3,4就取4,5,6,7,8就取8。對x向n取整用C語(yǔ)言的算術(shù)表達就是((x+n-1)/n)*n,當n為2的冪時(shí)可以將最后二步運算換成位操作——將最低 n - 1個(gè)二進(jìn)制位清 0就可以了。

va_arg(ap,t)就是從ap中取出類(lèi)型為t的數據,并將指針相應后移。如va_arg(ap, int)就表示取出一個(gè)int數據并將指針向移四個(gè)字節。

因此在函數中先用va_start()得到變參的起始地址,再用va_arg()一個(gè)一個(gè)取值,最后再用va_end()收尾就可以解析可變參數了。

 

第三步 vfprintf()函數和vsprintf()函數

vfprintf()這個(gè)函數很重要,光從名字上看就知道它與經(jīng)常使用的printf()函數有很大的關(guān)聯(lián)。它有多個(gè)重載版本,這里講解最常用的一種:

函數原型

int vfprintf(

   FILE *stream,

   const char *format,

   va_list argptr

);

第一個(gè)參數為一個(gè)FILE指針。FILE結構在C語(yǔ)言的讀寫(xiě)文件必不可少。要對屏幕輸出傳入stdout。

第二個(gè)參數指定輸出的格式。

第三個(gè)參數是va_list類(lèi)型,這個(gè)少見(jiàn),但其實(shí)就是一個(gè)char*表示可變參參數的起始地址。

返回值:成功返回輸出的字節數(不包括最后的’\0’),失敗返回-1。

vsprintf()與上面函數類(lèi)似,就只列出函數原型了:

int vsprintf(

   char *buffer,

   const char *format,

   va_list argptr

);

還有一個(gè)int _vscprintf(const char *format, va_list argptr );可以用來(lái)計算vsprintf()函數中的buffer字符串要多少字節的空間。

 

 

 

 

代碼范例

下面就給出了自己實(shí)現的printf()函數(注1)與WriteLine()函數

int Printf(char *pszFormat, ...) 

{

       va_list   pArgList;

      

       va_start(pArgList, pszFormat);

       int nByteWrite = vfprintf(stdout, pszFormat, pArgList);

       va_end(pArgList);

 

       return nByteWrite;

}

 

int WriteLine(char *pszFormat, ...)

{

       va_list   pArgList;

      

       va_start(pArgList, pszFormat);

       int nByteWrite = vfprintf(stdout, pszFormat, pArgList);

       if (nByteWrite != -1)

              putchar('\n'); //注2

       va_end(pArgList);

      

       return (nByteWrite == -1 ? -1 : nByteWrite + 1);

}

調用與printf()函數相同。

再給出一個(gè)用可變參數來(lái)求和,遺憾的在C,C++中無(wú)法確定傳入的可變參數的個(gè)數(printf()中是通過(guò)掃描'%'個(gè)數來(lái)確實(shí)參數的個(gè)數的),因此要么就要指定個(gè)數,要么在參數的最后要設置哨兵數值:

設置哨兵數值:

const int GUARDNUMBER = 0; //哨兵標識

//變參參數的個(gè)數無(wú)法確定,在printf()中是通過(guò)掃描'%'個(gè)數,在這通過(guò)設置哨兵標識來(lái)確定變參參數的終止

int MySum(int i, ...)

{

       int sum = i;

       va_list argptr;

      

       va_start(argptr, i);

       while ((i = va_arg(argptr, int)) != GUARDNUMBER)

              sum += i;

       va_end(argptr);

      

       return sum;

}

可以這樣的調用:   printf("%d\n", MySum(1, 3, 5, 7, 9, 0));

但不可以直接傳入一個(gè)0:   printf("%d\n", MySum(0)); //error

指定個(gè)數:

int MySum(int nCount, ...)

{

       if (nCount <= 0)

              return 0;

 

       int sum = 0;

       va_list argptr;

      

       va_start(argptr, nCount);

       for (int i = 0; i < nCount; i++)

              sum += va_arg(argptr, int);

       va_end(argptr);

      

       return sum;

}

調用時(shí)第一個(gè)參數表示后面參數的個(gè)數如:

       printf("%d\n", MySum(5, 1, 3, 5, 7, 9));

       printf("%d\n", MySum(0));

代碼所用的頭文件:

#include <stdarg.h>

#include <stdio.h>

 

可變參數的使用方法遠遠不止上述幾種,不過(guò)在C,C++中使用可變參數時(shí)要小心,在使用printf()等函數時(shí)傳入的參數個(gè)數一定不能比前面的格式化字符串中的’%’符號個(gè)數少,否則會(huì )產(chǎn)生訪(fǎng)問(wèn)越界,運氣不好的話(huà)還會(huì )導致程序崩潰。

 

可變參數的原形理涉及到調用函數時(shí)參數的入棧問(wèn)題,這個(gè)下次再開(kāi)一篇進(jìn)行專(zhuān)門(mén)的探討。

 

 

 

注1.    網(wǎng)上有不用vfprintf()自己解析參數來(lái)實(shí)現printf()的,但很少能將功能做到與printf()相近(實(shí)際上能完全熟悉printf()的人已經(jīng)就不多,不信的話(huà)可以先看看《C陷阱與缺陷》了解printf()很多不太常用的參數,再去Microsoft Visual Studio\VC98\CRT\SRC中查看OUTPUT.C對printf()的實(shí)現)。

注2.    如果輸出單個(gè)字符 putchar(ch)會(huì )比printf(“%c”, ch)效率高的多。在字符串不長(cháng)的情況下,多次調用putchar()也會(huì )比調用printf(“%s\n”, szStr);的效率高。在函數大量調用時(shí)非常明顯。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
C語(yǔ)言中可變參數的用法與實(shí)例
C語(yǔ)言可變參數函數的使用及相關(guān)函數介紹
<stdlib.h>包括的函數講解
考查嵌入式C開(kāi)發(fā)人員的最好的0x10道題
va_list、va_start、va_arg、va_end
C語(yǔ)言中可變參數的用法
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久