亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C/C++可變參數(shù)的使用

 更新時(shí)間:2013年09月14日 10:01:05   作者:  
可變參數(shù)的使用方法遠(yuǎn)遠(yuǎn)不止以下幾種,不過在C,C++中使用可變參數(shù)時(shí)要小心,在使用printf()等函數(shù)時(shí)傳入的參數(shù)個(gè)數(shù)一定不能比前面的格式化字符串中的’%’符號(hào)個(gè)數(shù)少,否則會(huì)產(chǎn)生訪問越界,運(yùn)氣不好的話還會(huì)導(dǎo)致程序崩潰

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

第一步 可變參數(shù)表示
用三個(gè)點(diǎn)…來表示,查看printf()函數(shù)和scanf()函數(shù)的聲明:
int printf(const char *, ...);
int scanf(const char *, ...);
這三個(gè)點(diǎn)用在宏中就是變參宏(Variadic Macros),默認(rèn)名稱為__VA_ARGS__。如:
#define WriteLine(...) { printf(__VA_ARGS__); putchar('\n');}
再WriteLine("MoreWindows");
考慮下printf()的返回值是表示輸出的字節(jié)數(shù)。將上面宏改成:
#define WriteLine (...) printf(__VA_ARGS__) + (putchar('\n') != EOF ? 1: 0);
這樣就可以得到WriteLine宏的返回值了,它將返回輸出的字節(jié)數(shù),包括最后的'\n'。如下例所示i和j都將輸出12。

復(fù)制代碼 代碼如下:

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

第二步 如何處理va_list類型
函數(shù)內(nèi)部對(duì)可變參數(shù)都用va_list及與它相關(guān)的三個(gè)宏來處理,這是實(shí)現(xiàn)變參參數(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) )

來分析這四個(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)小復(fù)雜了。( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )全是位操作,看起來有點(diǎn)麻煩,其實(shí)不然,非常簡(jiǎn)單的,就是取整到sizeof(int)。比如sizeof(int)為4,1,2,3,4就取4,5,6,7,8就取8。對(duì)x向n取整用C語言的算術(shù)表達(dá)就是((x+n-1)/n)*n,當(dāng)n為2的冪時(shí)可以將最后二步運(yùn)算換成位操作——將最低 n - 1個(gè)二進(jìn)制位清 0就可以了。
va_arg(ap,t)就是從ap中取出類型為t的數(shù)據(jù),并將指針相應(yīng)后移。如va_arg(ap, int)就表示取出一個(gè)int數(shù)據(jù)并將指針向移四個(gè)字節(jié)。

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

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

函數(shù)原型

復(fù)制代碼 代碼如下:

int vfprintf(
   FILE *stream,
   const char *format,
   va_list argptr
);

第一個(gè) 參數(shù)為一個(gè)FILE指針。FILE結(jié)構(gòu)在C語言的讀寫文件必不可少。要對(duì)屏幕輸出傳入stdout。
第二個(gè) 參數(shù)指定輸出的格式。
第三個(gè) 參數(shù)是va_list類型,這個(gè)少見,但其實(shí)就是一個(gè)char*表示可變參參數(shù)的起始地址。
返回值:成功返回輸出的字節(jié)數(shù)(不包括最后的'\0'),失敗返回-1。

vsprintf()與上面函數(shù)類似,就只列出函數(shù)原型了:
復(fù)制代碼 代碼如下:

int vsprintf(
   char *buffer,
   const char *format,
   va_list argptr
);

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

代碼范例
下面就給出了自己實(shí)現(xiàn)的printf()函數(shù)(注1)與WriteLine()函數(shù)
復(fù)制代碼 代碼如下:

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);
}

調(diào)用與printf()函數(shù)相同。
再給出一個(gè)用可變參數(shù)來求和,遺憾的在C,C++中無法確定傳入的可變參數(shù)的個(gè)數(shù)(printf()中是通過掃描'%'個(gè)數(shù)來確實(shí)參數(shù)的個(gè)數(shù)的),因此要么就要指定個(gè)數(shù),要么在參數(shù)的最后要設(shè)置哨兵數(shù)值:
設(shè)置哨兵數(shù)值:
復(fù)制代碼 代碼如下:

const int GUARDNUMBER = 0; //哨兵標(biāo)識(shí)
//變參參數(shù)的個(gè)數(shù)無法確定,在printf()中是通過掃描'%'個(gè)數(shù),在這通過設(shè)置哨兵標(biāo)識(shí)來確定變參參數(shù)的終止
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;
}

可以這樣的調(diào)用:   printf("%d\n", MySum(1, 3, 5, 7, 9, 0));
但不可以直接傳入一個(gè)0:   printf("%d\n", MySum(0)); //error
指定個(gè)數(shù):
復(fù)制代碼 代碼如下:

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;
}

調(diào)用時(shí)第一個(gè)參數(shù)表示后面參數(shù)的個(gè)數(shù)如:
復(fù)制代碼 代碼如下:

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

代碼所用的頭文件:
#include <stdarg.h>
#include <stdio.h>

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

相關(guān)文章

  • 深入C++中API的問題詳解

    深入C++中API的問題詳解

    本篇文章是對(duì)C++中API的問題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 使用opencv實(shí)現(xiàn)車道線檢測(cè)實(shí)戰(zhàn)代碼

    使用opencv實(shí)現(xiàn)車道線檢測(cè)實(shí)戰(zhàn)代碼

    這篇文章主要介紹了opencv車道線檢測(cè)實(shí)戰(zhàn),效果非常逼真,代碼簡(jiǎn)單易懂,對(duì)opencv車道線檢測(cè)實(shí)戰(zhàn)代碼感興趣的朋友一起看看吧
    2022-03-03
  • C語言代碼實(shí)現(xiàn)三子棋小游戲

    C語言代碼實(shí)現(xiàn)三子棋小游戲

    這篇文章主要為大家詳細(xì)介紹了C語言代碼實(shí)現(xiàn)三子棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • C++ 實(shí)戰(zhàn)開發(fā)一個(gè)猜單詞的小游戲

    C++ 實(shí)戰(zhàn)開發(fā)一個(gè)猜單詞的小游戲

    眾所周知紙上得來終覺淺,我們要在實(shí)戰(zhàn)中才能真正的掌握技術(shù),小編為大家?guī)硪环萦肅++編寫的猜單詞小游戲,給大家練練手,快來看看吧
    2021-11-11
  • C語言模擬實(shí)現(xiàn)簡(jiǎn)單掃雷游戲

    C語言模擬實(shí)現(xiàn)簡(jiǎn)單掃雷游戲

    這篇文章主要為大家詳細(xì)介紹了C語言模擬實(shí)現(xiàn)簡(jiǎn)單掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • C++重載的奧義之函數(shù)重載詳解

    C++重載的奧義之函數(shù)重載詳解

    函數(shù)重載是C++多態(tài)(靜態(tài)多態(tài))的特征體現(xiàn),它可以允許重復(fù)使用同一個(gè)函數(shù)名(籃子)的函數(shù),但是函數(shù)的參數(shù)列表(籃子裝的東西)是可以不一樣的。下面就簡(jiǎn)單講講C++中函數(shù)重載的相關(guān)應(yīng)用吧
    2023-04-04
  • C語言中的結(jié)構(gòu)體的入門學(xué)習(xí)教程

    C語言中的結(jié)構(gòu)體的入門學(xué)習(xí)教程

    這篇文章主要介紹了C語言中的結(jié)構(gòu)體的入門學(xué)習(xí)教程,以struct語句定義的結(jié)構(gòu)體是C語言編程中的重要基礎(chǔ),需要的朋友可以參考下
    2015-12-12
  • CFileDialog設(shè)置多選的問題解決

    CFileDialog設(shè)置多選的問題解決

    前幾天同事問我在CFileDialog中多選時(shí)按確定按鈕后DoModal函數(shù)的返回值是IDCANCEL的問題解決
    2013-02-02
  • OpenCV 圖像拼接和圖像融合的實(shí)現(xiàn)

    OpenCV 圖像拼接和圖像融合的實(shí)現(xiàn)

    本文主要介紹了OpenCV 圖像拼接和圖像融合,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • C/C++中提高查找速度的小技巧

    C/C++中提高查找速度的小技巧

    這篇文章主要給大家介紹了C/C++中提高數(shù)組中查找某個(gè)元素或者字符串中查找某個(gè)字符效率的小技巧,提高速度對(duì)我們?nèi)粘i_發(fā)來說還是很有用的,文中給出了詳細(xì)的示例代碼,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-01-01

最新評(píng)論