程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C/C++可變參數的應用

C/C++可變參數的應用

編輯:關於C++

C/C++可變參數的應用。本站提示廣大學習愛好者:(C/C++可變參數的應用)文章只能為提供參考,不一定能成為您想要的結果。以下是C/C++可變參數的應用正文


可變參數即表現參數個數可以變更,可多可少,也表現參數的類型也能夠變更,可所以int,double還可所以char*,類,構造體等等。可變參數是完成printf(),sprintf()等函數的症結的地方,也能夠用可變參數來對隨意率性數目的數據停止乞降,求均勻值帶來便利(否則就用數組或每種寫個重載)。在C#中有專門的症結字parame,但在C,C++並沒有相似的語法,不外幸虧供給這方面的處置函數,本文將重點引見若何應用這些函數。

第一步 可變參數表現
用三個點…來表現,檢查printf()函數和scanf()函數的聲明:
int printf(const char *, ...);
int scanf(const char *, ...);
這三個點用在宏中就是變參宏(Variadic Macros),默許稱號為__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類型
函數外部對可變參數都用va_list及與它相干的三個宏來處置,這是完成變參參數的症結的地方。

在<stdarg.h>中可以找到va_list的界說:
typedef char *  va_list;
再引見與它關系親密的三個宏要引見下:va_start(),va_end()和va_arg()。

異樣在<stdarg.h>中可以找到這三個宏的界說:
#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) )

來剖析這四個宏:
va_end(ap)這個最簡略,就是將指針置成NULL。
va_start(ap,v)中ap = (va_list)&v + _INTSIZEOF(v)先是取v的地址,再加上_INTSIZEOF(v)。_INTSIZEOF(v)就有點小龐雜了。( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )滿是位操作,看起來有點費事,其實否則,異常簡略的,就是取整到sizeof(int)。好比sizeof(int)為4,1,2,3,4就取4,5,6,7,8就取8。對x向n取整用C說話的算術表達就是((x+n-1)/n)*n,當n為2的冪時可以將最初二步運算換成位操作——將最低 n - 1個二進制位清 0便可以了。
va_arg(ap,t)就是從ap中掏出類型為t的數據,並將指針響應後移。如va_arg(ap, int)就表現掏出一個int數據並將指針向移四個字節。

是以在函數中先用va_start()獲得變參的肇端地址,再用va_arg()一個一個取值,最初再用va_end()掃尾便可以解析可變參數了。

第三步 vfprintf()函數和vsprintf()函數
vfprintf()這個函數很主要,光從名字上看就曉得它與常常應用的printf()函數有很年夜的聯系關系。它有多個重載版本,這裡講授最經常使用的一種:

函數原型

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

第一個 參數為一個FILE指針。FILE構造在C說話的讀寫文件必弗成少。要對屏幕輸入傳入stdout。
第二個 參數指定輸入的格局。
第三個 參數是va_list類型,這個少見,但其實就是一個char*表現可變參參數的肇端地址。
前往值:勝利前往輸入的字節數(不包含最初的'\0'),掉敗前往-1。

vsprintf()與下面函數相似,就只列出函數原型了:

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

還有一個int _vscprintf(const char *format, va_list argptr );可以用來盤算vsprintf()函數中的buffer字符串要若干字節的空間。

代碼典范
上面就給出了本身完成的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()函數雷同。
再給出一個用可變參數來乞降,遺憾的在C,C++中沒法肯定傳入的可變參數的個數(printf()中是經由過程掃描'%'個數來確切參數的個數的),是以要末就要指定個數,要末在參數的最初要設置尖兵數值:
設置尖兵數值:

const int GUARDNUMBER = 0; //尖兵標識
//變參參數的個數沒法肯定,在printf()中是經由過程掃描'%'個數,在這經由過程設置尖兵標識來肯定變參參數的終止
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));
但弗成以直接傳入一個0:   printf("%d\n", MySum(0)); //error
指定個數:

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

挪用時第一個參數表現前面參數的個數如:

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

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

可變參數的應用辦法遠遠不止上述幾種,不外在C,C++中應用可變參數時要當心,在應用printf()等函數時傳入的參數個數必定不克不及比後面的格局化字符串中的'%'符號個數少,不然會發生拜訪越界,命運運限欠好的話還會招致法式瓦解。

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