C/C++中不定參數(shù)的使用詳解
C語言的不定參
C語言的不定參數(shù)最常見的應(yīng)用示例就是printf函數(shù),如下,參數(shù)列表中的...表示不定參數(shù)列表
#include <stdio.h> int printf(const char *format, ...);
試著模擬實現(xiàn)C語言的printf函數(shù)
void myprintf(const char *fmt, ...) { //TODO }
C語言中,對于...不定參列表,要用va_*系列宏函數(shù)操作
#include <stdarg.h> ???????void va_start(va_list ap, last); type va_arg(va_list ap, type); void va_end(va_list ap); void va_copy(va_list dest, va_list src);
va_list
va_list可以理解為一個指針類型,開始時,通過調(diào)用va_start,它會指向不定參列表的第一個參數(shù)
va_start
我們知道,C/C++的函數(shù)參數(shù)通過壓棧的方式傳入,不定參列表的多個參數(shù)也需要壓棧。
va_start的作用是使ap指向不定參列表的第一個參數(shù)。通過不定參數(shù)列表前的最后一個函數(shù)參數(shù),找到不定參列表的首元素,并使ap(va_list類型的指針)指向首元素。因此,C函數(shù)使用...不定參數(shù),前面至少包含一個其它參數(shù),由它提供不定參數(shù)的起始位置。
va_arg
va_arg的作用是在不定參數(shù)列表中,從ap指向的參數(shù)開始,逐個返回type類型的數(shù)據(jù),一般需要循環(huán)調(diào)用va_arg,在此過程中ap會不斷往后走
va_end
ap使用結(jié)束后就失效了,為了避免野指針的引用,va_end可以銷毀ap指針
va_copy
拷貝src到dest,使得二者指向同一個不定參數(shù)列表,src不用再次調(diào)用va_start,但要調(diào)用va_end
Test Demo:
void myprintf(size_t num, ...) { va_list ap1; va_start(ap1, num); va_list ap2; va_copy(ap2, ap1); for (int i = 0; i < num; i++) { char ch = va_arg(ap1, int); std::cout << ch; } std::cout << std::endl; for (int i = 0; i < num; i++) { char ch = va_arg(ap2, int); std::cout << ch; } std::cout << std::endl; va_end(ap1); va_end(ap2); } int main() { myprintf(3, 'L', 'O', 'L'); return 0; }
輸出結(jié)果
[ckf@VM-8-12-centos 1.before]$ ./vargs
LOL
LOL
注意:va_arg對于可變參數(shù)的處理是有一些規(guī)則的,特別是對于小整數(shù)類型(如char和float)。這些類型在傳遞給va_arg時會被默認(rèn)轉(zhuǎn)換為int和double,而不是它們的實際類型。因此,在Test Demo中,對于傳入的char類型參數(shù),在調(diào)用va_arg時也應(yīng)該指定type為int,獲得返回值后再轉(zhuǎn)換為實際類型char。
以下函數(shù)可以對不定參數(shù)列表進(jìn)行格式化操作。
#include <stdarg.h> int vprintf(const char *format, va_list ap); int vfprintf(FILE *stream, const char *format, va_list ap); int vsprintf(char *str, const char *format, va_list ap); int vsnprintf(char *str, size_t size, const char *format, va_list ap);
它們的作用與printf相同,都可以通過參數(shù)format,對不定參數(shù)進(jìn)行格式化。區(qū)別在于:printf使用不定參...作為格式化的數(shù)據(jù),而上面以v開頭printf結(jié)尾的函數(shù),使用ap指向的不定參數(shù)列表作為格式化的數(shù)據(jù)。除此之外,內(nèi)部的區(qū)別就在于輸出的方向了,vprintf將格式化后的字符串輸出到stdout,vfprintf輸出到指定的文件流,vsprintf和vsprintf輸出到指定的內(nèi)存空間str,且后者可以指定輸出的字節(jié)個數(shù)。
Test Demo:
void myprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); char str[64] = {0}; int len = vsnprintf(str, sizeof(str), fmt, ap); str[len] = 0; std::cout << str << std::endl; va_end(ap); } int main() { myprintf("%s %c %d", "你好", '!', 2024); return 0; }
輸出結(jié)果
[ckf@VM-8-12-centos 1.before]$ ./vargs
你好 ! 2024
C++的不定參
補(bǔ)充:
- args參數(shù)包作為參數(shù)傳遞給另一個函數(shù)時,記得加...,表示這個args參數(shù)是不定參數(shù)包
- 函數(shù)接收Args...類型的參數(shù)包時,通??梢詫?shù)設(shè)置為&&萬能引用,減少拷貝的成本
- C++11標(biāo)準(zhǔn)庫中,很多構(gòu)造方法都使用了以不定參數(shù)包為參數(shù)的條目,方便一些無法缺點參數(shù)個數(shù)的實例的構(gòu)造
例如:
std::make_shared,由于并不確定構(gòu)造智能指針指向的對象類型需要傳入多少參數(shù),C++11使用了Args不定參數(shù)包
?
emplace函數(shù),C++11很多容器都重載了這個函數(shù),emplace支持可變參數(shù)包,并且用參數(shù)包中的參數(shù)作為新插入元素構(gòu)造函數(shù)的參數(shù)。
Test Demo
template <class T> void myprintfcpp(T val) // 終止函數(shù) { std::cout << val; } template <class T, class... Args> void myprintfcpp(T val, Args &&...args) { std::cout << val; myprintfcpp(std::forward<Args>(args)...); } int main() { myprintfcpp(3, 'L', 'O', 'L'); std::cout << std::endl; return 0; }
輸出結(jié)果
[ckf@VM-8-12-centos 1.before]$ ./vargs
3LOL
到此這篇關(guān)于C/C++中不定參數(shù)的使用詳解的文章就介紹到這了,更多相關(guān)C++不定參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解vs2022創(chuàng)建及調(diào)用.lib的方法
這篇文章主要介紹了vs2022創(chuàng)建及調(diào)用.lib的方法,調(diào)用Lib的原則就是可以讓編譯器找到頭文件和庫文件的目錄,并正確引入,本文給大家詳細(xì)講解需要的朋友可以參考下2022-11-11