柚子快報(bào)激活碼778899分享:C語(yǔ)言和C++中不定參數(shù)解析
柚子快報(bào)激活碼778899分享:C語(yǔ)言和C++中不定參數(shù)解析
你所看到的驚艷,都曾被平庸歷練
文章目錄
簡(jiǎn)介C語(yǔ)言不定參數(shù)不定參宏函數(shù)
C++不定參數(shù)方法一:遞歸展開(kāi)方式二:折疊表達(dá)式方法三:逗號(hào)表達(dá)式
總結(jié)
簡(jiǎn)介
相信學(xué)過(guò)c/c++的佬們都知道,如果一個(gè)函數(shù)將自己的參數(shù)確定好后,要想使用該函數(shù)就必須傳遞合適的數(shù)量以及類(lèi)型的參數(shù),然而這樣的函數(shù)非常具有局限性。例如有一個(gè)求和函數(shù),我們并不知道我們要求幾個(gè)數(shù)的和,這就導(dǎo)致在確定函數(shù)參數(shù)時(shí)無(wú)從下手,而這時(shí)候不定參數(shù)就派上了用場(chǎng)。
不定參數(shù)是指在函數(shù)定義時(shí),允許接收可變數(shù)量的參數(shù)。這種機(jī)制允許函數(shù)在調(diào)用時(shí)接受不同數(shù)量的實(shí)際參數(shù),使得函數(shù)更加靈活,能夠適應(yīng)不同的使用場(chǎng)景。例如C語(yǔ)言中的printf函數(shù),scanf函數(shù)等。在C和C++中,不定參數(shù)的實(shí)現(xiàn)方式主要依賴(lài)于標(biāo)準(zhǔn)庫(kù)中的stdarg.h頭文件。
在使用不定參數(shù)后,sum函數(shù)可以接受不同數(shù)量的參數(shù),并計(jì)算它們的總和。這種靈活性使得函數(shù)能夠適應(yīng)不同的求和需求,而不需要為每種情況都定義一個(gè)單獨(dú)的函數(shù)。這樣的設(shè)計(jì)使代碼更簡(jiǎn)潔,更容易擴(kuò)展,同時(shí)提供了更大的通用性。
不定參數(shù)的優(yōu)勢(shì):
優(yōu)勢(shì)說(shuō)明靈活性不定參數(shù)函數(shù)允許在調(diào)用函數(shù)時(shí)傳遞不同數(shù)量的參數(shù),提高了函數(shù)的靈活性和通用性。適應(yīng)變化在處理不確定數(shù)量的參數(shù)或者未來(lái)可能會(huì)新增參數(shù)的情況下,不定參數(shù)函數(shù)能夠更好地適應(yīng)變化。簡(jiǎn)化代碼使用不定參數(shù)可以簡(jiǎn)化函數(shù)定義,避免定義多個(gè)函數(shù)處理不同數(shù)量的參數(shù)情況??勺x性在某些情況下,使用不定參數(shù)可以使函數(shù)調(diào)用更加清晰和可讀,特別是當(dāng)參數(shù)的數(shù)量可能變化時(shí)。
C語(yǔ)言不定參數(shù)
在C語(yǔ)言中,不定參數(shù)是通過(guò)stdarg.h頭文件提供的一組宏來(lái)實(shí)現(xiàn)的。這些宏主要包括va_list、va_start、va_arg和va_end。
va_list: va_list是一個(gè)類(lèi)型,用于聲明一個(gè)變量,該變量將用于存儲(chǔ)不定參數(shù)的信息。 va_start: va_start宏用于初始化va_list,使其指向不定參數(shù)的起始位置。它接受兩個(gè)參數(shù),第一個(gè)是va_list對(duì)象,第二個(gè)是最后一個(gè)確定的參數(shù),用于確定不定參數(shù)的起始位置。 void function_with_varargs(int fixed_arg, ...) {
va_list args;
va_start(args, fixed_arg); // 現(xiàn)在args指向第一個(gè)可變參數(shù)
// ...
va_end(args);
}
va_arg: va_arg宏用于獲取當(dāng)前位置的值,并且在每次調(diào)用后,會(huì)將指針移動(dòng)到下一個(gè)可變參數(shù)的位置。它接受兩個(gè)參數(shù),第一個(gè)是va_list對(duì)象,第二個(gè)是要獲取的參數(shù)的類(lèi)型。 int value = va_arg(args, int);
va_end: va_end宏用于清理va_list對(duì)象,確保在使用完不定參數(shù)后正確釋放資源。 va_end(args);
如下是一個(gè)在C語(yǔ)言中使用不定參數(shù)的求和函數(shù):
#include
#include
int sum(int n, ...) {
va_list args; // 定義用于存儲(chǔ)不定參數(shù)信息的變量
va_start(args, n); // 初始化 va_list,使其指向不定參數(shù)列表的起始位置
int ret = 0;
for (int i = 0; i < n; i++) {
int tmp = va_arg(args, int); // 獲取當(dāng)前位置的參數(shù)值
ret += tmp;
}
va_end(args); // 清理 va_list,確保資源正確釋放
return ret;
}
int main() {
int ret = sum(5, 10, 24, 10, 34, 0); // 調(diào)用 sum 函數(shù),傳遞5個(gè)整數(shù)
printf("%d\n", ret); // 打印計(jì)算結(jié)果
return 0;
}
在 sum 函數(shù)中,va_start 初始化了 va_list,并使其指向傳遞給函數(shù)的不定參數(shù)的起始位置。然后,通過(guò)使用 va_arg 獲取每個(gè)參數(shù)的值,并將它們累加到 ret 變量中。最后,通過(guò) va_end 清理 va_list,確保資源得到正確釋放。
在 main 函數(shù)中,調(diào)用了 sum 函數(shù),并將 5 個(gè)整數(shù)作為參數(shù)傳遞給它,然后打印計(jì)算結(jié)果。
不定參宏函數(shù)
除此之外,還可以在C語(yǔ)言中使用宏來(lái)創(chuàng)建帶有不定參數(shù)的宏函數(shù)。不定參數(shù)的宏函數(shù)通常使用__VA_ARGS__來(lái)表示可變數(shù)量的參數(shù)。
#include
#include
// 定義 LOG 宏,使用 __VA_ARGS__ 來(lái)表示可變參數(shù)
#define LOG(fmt, ...) printf("[%s : %d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
int main() {
// 使用 LOG 宏輸出日志信息,自動(dòng)包含文件名和行號(hào)
LOG("登陸失敗");
return 0;
}
在這個(gè)例子中,LOG 宏使用了 __VA_ARGS__ 來(lái)表示可變參數(shù)。在調(diào)用 LOG 時(shí),傳遞的字符串會(huì)被輸出,并自動(dòng)包含文件名和行號(hào)。這樣,通過(guò)這個(gè)宏,您可以輕松地在代碼中輸出帶有文件名和行號(hào)的日志信息。
需要注意的是,在 ##__VA_ARGS__ 中的 ## 用于處理不帶參數(shù)時(shí)的情況,以防止在宏展開(kāi)時(shí)產(chǎn)生語(yǔ)法錯(cuò)誤。在可變參數(shù)為空的情況下,##__VA_ARGS__ 將會(huì)被移除,避免了末尾逗號(hào)的問(wèn)題。
其中 filename.c 是當(dāng)前文件名,7 是當(dāng)前行號(hào),登陸失敗 是通過(guò) LOG 宏傳遞的字符串。不定參數(shù)宏函數(shù)的使用可以幫助簡(jiǎn)化代碼,但也需要小心使用,確保在宏展開(kāi)時(shí)沒(méi)有意外的副作用。
C++不定參數(shù)
C++中的不定參函數(shù)通常使用可變參數(shù)模板來(lái)實(shí)現(xiàn),這使得函數(shù)能夠接受不定數(shù)量和類(lèi)型的參數(shù)。使用可變參數(shù)模板的不定參函數(shù)是 C++11 引入的特性。如果你使用的是更早版本的 C++,可能需要使用
基本模板:
template
void print(Args... args) {}
又由于無(wú)法直接獲取參數(shù)包args中的每個(gè)參數(shù),所以只能通過(guò)展開(kāi)參數(shù)包的方式來(lái)獲取參數(shù)包中的每個(gè)參數(shù),這是使用可變模版參數(shù)的一個(gè)主要特點(diǎn),也是最大的難點(diǎn),即如何展開(kāi)可變模版參數(shù)。由于語(yǔ)法不支持使用args[i]這樣方式獲取可變參數(shù),所以只能想一些特殊的辦法來(lái)獲取參數(shù)包的值。
方法一:遞歸展開(kāi)
遞歸展開(kāi)可變參數(shù)包是使用可變參數(shù)模板的一種常見(jiàn)技術(shù),通常用于在編譯時(shí)展開(kāi)不定數(shù)量的參數(shù)。下面是一個(gè)遞歸展開(kāi)可變參數(shù)包的示例:
#include
void print() {
// 終止條件,處理空參數(shù)包
}
template
void print(T first, Args... args) {
std::cout << "Cur : " << first << " args size : " << sizeof...(args) << std::endl;
print(args...); // 遞歸調(diào)用,展開(kāi)參數(shù)包
}
int main() {
print("你干嘛", "哎呦", 100, 345);
return 0;
}
這個(gè)程序定義了一個(gè)函數(shù)模板 print,該函數(shù)接受任意數(shù)量和類(lèi)型的參數(shù),并遞歸展開(kāi)這些參數(shù)。
print 函數(shù)有兩個(gè)版本:一個(gè)是終止條件版本(空參數(shù)包時(shí)調(diào)用),另一個(gè)是遞歸版本。 在遞歸版本中,首先打印第一個(gè)參數(shù) first 和參數(shù)包的大?。ㄊ褂?sizeof...(args)),然后通過(guò) print(args...) 遞歸地調(diào)用自己,展開(kāi)參數(shù)包。 在 main 函數(shù)中,你調(diào)用了 print 函數(shù),傳遞了不同類(lèi)型的參數(shù)。
這樣,當(dāng)你運(yùn)行程序時(shí),print 函數(shù)將遞歸展開(kāi)參數(shù)包,打印每個(gè)參數(shù)的值和參數(shù)包的大小。
這樣,通過(guò)遞歸調(diào)用,編譯器會(huì)在編譯時(shí)展開(kāi)參數(shù)包,使得函數(shù)能夠處理不定數(shù)量和類(lèi)型的參數(shù)。這是一種在編譯時(shí)進(jìn)行模板展開(kāi)的方式,相比運(yùn)行時(shí)的展開(kāi)更加高效。
方式二:折疊表達(dá)式
除了遞歸展開(kāi)參數(shù)包的方式,C++17 引入了折疊表達(dá)式(fold expressions)的特性,這是一種更簡(jiǎn)潔的方式來(lái)展開(kāi)參數(shù)包。折疊表達(dá)式在處理可變參數(shù)包時(shí)可以提供更緊湊的語(yǔ)法。如下代碼:
#include
// 使用折疊表達(dá)式展開(kāi)參數(shù)包
template
void print(Args... args) {
(std::cout << ... << args) << std::endl; // 折疊表達(dá)式展開(kāi)參數(shù)包
}
int main() {
print("你干嘛", "哎呦", 100, 345);
return 0;
}
在這個(gè)例子中,(std::cout << ... << args) 是一個(gè)折疊表達(dá)式,用于展開(kāi)參數(shù)包 args。這個(gè)表達(dá)式實(shí)際上將所有參數(shù)連接到 std::cout 流中,然后通過(guò) << std::endl 添加換行符。
當(dāng)需要使用折疊表達(dá)式求和時(shí),也可以如下代碼:
#include
template
int sum(Args... args) {
return (args + ...);
}
int main() {
std::cout << sum(25, 34, 59) << std::endl;
return 0;
}
代碼中使用了 C++17 中引入的折疊表達(dá)式 (args + ...) 來(lái)計(jì)算參數(shù)包中所有參數(shù)的和。在這個(gè)例子中,折疊表達(dá)式展開(kāi)了 args 中的參數(shù),并使用 + 運(yùn)算符對(duì)它們求和。
使用折疊表達(dá)式的好處是語(yǔ)法更為緊湊,而且可以在一個(gè)表達(dá)式中完成參數(shù)包的展開(kāi)。這是在 C++17 及更高版本中的一種更現(xiàn)代的方式。
總體而言,遞歸展開(kāi)和折疊表達(dá)式是兩種常見(jiàn)的方式,具體選擇取決于個(gè)人或團(tuán)隊(duì)的偏好以及編譯器的支持版本。在 C++17 及更高版本中,折疊表達(dá)式通常被認(rèn)為是更好的選擇。
方法三:逗號(hào)表達(dá)式
除了遞歸展開(kāi)和折疊表達(dá)式,還有一種使用逗號(hào)表達(dá)式的方式展開(kāi)參數(shù)包。這種方式通常結(jié)合逗號(hào)運(yùn)算符 , 和初始化列表來(lái)實(shí)現(xiàn)。
以下是一個(gè)示例:
#include
// 使用逗號(hào)表達(dá)式展開(kāi)參數(shù)包
template
void print(Args... args) {
int dummy[] = {(std::cout << args << " ", 0)...}; // 逗號(hào)表達(dá)式展開(kāi)參數(shù)包
(void)dummy; // 防止編譯器警告未使用的變量
std::cout << std::endl;
}
int main() {
print("你干嘛", "哎呦", 100, 345);
return 0;
}
在這個(gè)例子中,逗號(hào)表達(dá)式 (std::cout << args << " ", 0) 被用于展開(kāi)參數(shù)包 args。逗號(hào)表達(dá)式的返回值是初始化列表中的最后一個(gè)表達(dá)式的值(在這里是 0),而初始化列表的目的是為了創(chuàng)建一個(gè)臨時(shí)數(shù)組 dummy。
這種方式相對(duì)較獨(dú)特,通常在一些特殊情況下使用。一般而言,遞歸展開(kāi)和折疊表達(dá)式更為常見(jiàn)和直觀,但了解這種逗號(hào)表達(dá)式的方法也是有益的。選擇展開(kāi)參數(shù)包的方法通常取決于個(gè)人或團(tuán)隊(duì)的偏好、代碼可讀性和編譯器支持。
總結(jié)
在C語(yǔ)言和C++中,可變參數(shù)是一種強(qiáng)大的特性,它允許函數(shù)接受可變數(shù)量和類(lèi)型的參數(shù)。在C語(yǔ)言中,我們通常使用
C語(yǔ)言中的可變參數(shù):
使用
引入了可變參數(shù)模板,允許在編譯時(shí)處理可變數(shù)量和類(lèi)型的參數(shù)。提高了類(lèi)型安全性,無(wú)需手動(dòng)管理參數(shù)的類(lèi)型和數(shù)量??梢允褂眠f歸展開(kāi)、折疊表達(dá)式、逗號(hào)表達(dá)式等多種方式展開(kāi)可變參數(shù)包。 遞歸展開(kāi):
使用遞歸函數(shù)模板,逐一處理參數(shù)包中的每個(gè)參數(shù)。通過(guò)終止條件和遞歸調(diào)用來(lái)展開(kāi)參數(shù)包。 折疊表達(dá)式:
在C++17及以后版本引入,提供了更緊湊的語(yǔ)法。使用(expression op ...)的形式,其中op可以是二元運(yùn)算符。 逗號(hào)表達(dá)式:
使用逗號(hào)表達(dá)式展開(kāi)參數(shù)包時(shí),返回值不能直接用于數(shù)組初始化,通常使用0作為占位符??梢酝ㄟ^(guò)逗號(hào)表達(dá)式在一行中執(zhí)行多個(gè)操作。
在選擇可變參數(shù)的處理方式時(shí),應(yīng)根據(jù)具體情況和編程需求來(lái)選擇最合適的方法。C++中的可變參數(shù)模板提供了更強(qiáng)大、類(lèi)型安全和靈活的處理方式,但對(duì)于特定情況,C語(yǔ)言中的可變參數(shù)也可能是一種合適的選擇。最終,可變參數(shù)的使用應(yīng)該以代碼的清晰性、可讀性和維護(hù)性為重要考慮因素。
最后,碼文不易,如果文章對(duì)你有所幫助的話(huà),不妨點(diǎn)上一個(gè)?,感謝大佬的支持!
柚子快報(bào)激活碼778899分享:C語(yǔ)言和C++中不定參數(shù)解析
推薦閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。