可變引數函式的基本原理及使用實現

2021-08-22 15:07:04 字數 2699 閱讀 4255

本文主要介紹可變引數的函式使用,然後分析它的原理,程式設計師自己如何對它們實現和封裝,最後是可能會出現的問題和避免措施。

va函式(variable argument function),引數個數可變函式,又稱可變引數函式。c/c++程式設計中,系統提供給程式設計人員的va函式很少。*printf()/*scanf()系列函式,用於輸入輸出時格式化字串;exec*()系列函式,用於在程式中執行外部檔案(main(int argc,char*argv算不算呢,與其說main()也是乙個可變引數函式,倒不如說它是exec*()經過封裝後的具備特殊功能和意義的函式,至少在原理這一級上有

很多相似之處)。由於引數個數的不確定,使va函式具有很大的靈活性,易用性,對沒有使用過可變引數函式的程式設計人員很有**力;那麼,該如何編寫自己的va函式,va函式的運用時機、編譯實現又是如何。作者借本文談談自己關於va函式的一些淺見。

一、 從printf()開始

從大家都很熟悉的格式化字串函式開始介紹可變引數函式。

原型:int printf(const char * format, ...);

引數format表示如何來格式字串的指令,…

表示可選引數,呼叫時傳遞給"..."的引數可有可無,根據實際情況而定。

系統提供了vprintf系列格式化字串的函式,用於程式設計人員封裝自己的i/o函式。

int vprintf / vscanf(const char * format, va_list ap); // 從標準輸入/輸出格式化字串

int vfprintf / vfsacanf(file * stream, const char * format, va_list ap);

// 從檔案流

int vsprintf / vsscanf(char * s, const char * format, va_list ap); // 從字串

// 例1:格式化到乙個檔案流,可用於日誌檔案

file *logfile;

int writelog(const char * format, ...)

…// 呼叫時,與使用printf()沒有區別。

writelog("%04d-%02d-%02d %02d:%02d:%02d  %s/%04d logged out.", 

nyear, nmonth, nday, nhour, nminute, szusername, nuserid);

同理,也可以從檔案中執行格式化輸入;或者對標準輸入輸出,字串執行格式化。在上面的例1中,writelog()函式可以接受引數個數可變的輸入,本質上,它的實現需要vprintf()的支援。如何真正實現屬於自己的可變引數函式,包括控制每乙個傳入的可選引數。

二、 va函式的定義和va巨集

c語言支援va函式,作為c語言的擴充套件--c++同樣支援va函式,但在c++中並不推薦使用,c++引入的多型性同樣可以實現引數個數可變的函式。不過,c++的過載功能畢竟只能是有限多個可以預見的引數個數。比較而言,c中的va函式則可以定義無窮多個相當於c++的過載函式,這方面c++是無能為力的。va函式的優勢表現在使用的方便性和易用性上,可以使**更簡潔。c編譯器為了統一在不同的硬體架構、硬體平台上的實現,和增加**的可移植性,提供了一系列巨集來遮蔽硬體環境不同帶來的差異。

ansi c標準下,va的巨集定義在stdarg.h中,它們有:va_list,va_start(),va_arg(),va_end()。

// 例2:求任意個自然數的平方和:

int sqsum(int n1, ...)

va_end(arg_ptr);

return nsqsum;

}// 呼叫時

int nsqsum = sqsum(7, 2, 7, 11, -1);

可變引數函式的原型宣告格式為:

type vafunction(type arg1, type arg2, … );

引數可以分為兩部分:個數確定的固定引數和個數可變的可選引數。函式至少需要乙個固定引數,固定引數的宣告和普通函式一樣;可選引數由於個數不確定,宣告時用"…"表示。固定引數和可選引數公同構成乙個函式的引數列表。

借助上面這個簡單的例2,來看看各個va_***的作用:

va_list arg_ptr:定義乙個指向個數可變的引數列表指標;

va_start(arg_ptr, argn):使引數列表指標arg_ptr指向函式引數列表中的第乙個可選引數,說明:argn是位於第乙個可選引數之前的固定引數,(或者說,最後乙個固定引數;…之前的乙個引數),函式引數列表中引數在記憶體中的順序與函式宣告時的順序是一致的。如果有一va函式的宣告是void va_test(char a, char b, char c, …),則它的固定引數依次是a,b,c,最後乙個固定引數argn為c,因此就是

va_start(arg_ptr, c)。

va_copy(dest, src):dest,src的型別都是va_list,va_copy()用於複製引數列表指標,將dest初始化為src。

va_end(arg_ptr):清空引數列表,並置引數指標arg_ptr無效。

說明:指標arg_ptr被置無效後,可以通過呼叫va_start()、va_copy()恢復arg_ptr。每次呼叫va_st

art() / va_copy()後,必須得有相應的va_end()與之匹配。引數指標可以在引數列表中隨意地來回移動,但必須在va_start() … va_end()之內。

mysql的基本原理 Mysql 基本原理

mysql 基本原理 mysql是一種關聯式資料庫管理系統,關聯式資料庫將資料儲存在不同的表中,而不是將所有資料放在乙個大倉庫內,這樣就增加了速度並提高了靈活性 ysql是資料庫登入命令 uroot預設超級使用者登入 p 預設沒密碼 中寫密碼 mysqladmin uroot password 12...

爬蟲基本原理及概念

爬蟲在網路中爬行的時候,將web 上的網頁集合看成是乙個有向圖,從給定的起始 1 深度優先演算法 該演算法是指網路爬蟲會從選定的乙個超連結開始,按照一條線路,乙個乙個鏈結訪 問下去,直到達到這條線路的葉子節點,即不包含任何超連結的html 檔案,處理完這 到達葉子結點。這個方法有個優點是網路爬蟲在設...

MapReduce基本原理及應用

一 mapreduce模型簡介 mapreduce將複雜的 執行於大規模集群上的平行計算過程高度地抽象到了兩個函式 map和reduce。它採用 分而治之 策略,乙個儲存在分布式檔案系統中的大規模資料集,會被切分成許多獨立的分片 split 這些分片可以被多個map任務並行處理 1.map和redu...