這部分解釋了舊的 C 風(fēng)格變長(zhǎng)參數(shù)列表。了解這些內(nèi)容很重要,因?yàn)槟憧赡軙?huì)在遺留代碼中遇到它們。然而,在新代碼中,你應(yīng)該使用變參模板來實(shí)現(xiàn)類型安全的變長(zhǎng)參數(shù)列表。
考慮 C 函數(shù) printf(),來自 <cstdio>。你可以用任意數(shù)量的參數(shù)調(diào)用它:
printf("int %d/n", 5);printf("String %s and int %d/n", "hello", 5);printf("Many ints: %d, %d, %d, %d, %d/n", 1, 2, 3, 4, 5);
C/C++ 提供了語法和一些實(shí)用宏,用于編寫你自己的變長(zhǎng)參數(shù)函數(shù)。這些函數(shù)通常看起來很像 printf()。盡管你不經(jīng)常需要這個(gè)特性,但偶爾你會(huì)遇到它相當(dāng)有用的情況。例如,假設(shè)你想編寫一個(gè)快速而簡(jiǎn)單的調(diào)試函數(shù),當(dāng)設(shè)置了調(diào)試標(biāo)志時(shí),該函數(shù)將字符串打印到 stderr,但如果沒有設(shè)置調(diào)試標(biāo)志,則不執(zhí)行任何操作。就像 printf() 一樣,這個(gè)函數(shù)應(yīng)該能夠打印具有任意數(shù)量和任意類型參數(shù)的字符串。一個(gè)簡(jiǎn)單的實(shí)現(xiàn)如下:
#include <cstdio>#include <cstdarg>bool debug { false };void debugOut(const char* str, ...) { va_list ap; if (debug) { va_start(ap, str); vfprintf(stderr, str, ap); va_end(ap); }}
首先,請(qǐng)注意 debugOut() 的原型包含一個(gè)類型化且命名的參數(shù) str,后面跟著 ...(省略號(hào))。它們代表任意數(shù)量和類型的參數(shù)。要訪問這些參數(shù),你必須使用 <cstdarg> 中定義的宏。你聲明一個(gè) va_list 類型的變量,并用 va_start 調(diào)用進(jìn)行初始化。va_start() 的第二個(gè)參數(shù)必須是參數(shù)列表中最右邊的命名變量。所有具有變長(zhǎng)參數(shù)列表的函數(shù)都至少需要一個(gè)命名參數(shù)。debugOut() 函數(shù)簡(jiǎn)單地將這個(gè)列表傳遞給 vfprintf()(<cstdio> 中的標(biāo)準(zhǔn)函數(shù))。vfprintf() 調(diào)用返回后,debugOut() 調(diào)用 va_end() 來終止訪問變量參數(shù)列表。在調(diào)用 va_start() 后,你必須始終調(diào)用 va_end(),以確保函數(shù)以一致的堆棧狀態(tài)結(jié)束。你可以如下方式使用該函數(shù):
debug = true;debugOut("int %d/n", 5);debugOut("String %s and int %d/n", "hello", 5);debugOut("Many ints: %d, %d, %d, %d, %d/n", 1, 2, 3, 4, 5);
如果你想自己訪問實(shí)際參數(shù),你可以使用 va_arg() 來做到這一點(diǎn)。它接受 va_list 作為第一個(gè)參數(shù),以及要解釋的參數(shù)的類型。不幸的是,除非你提供明確的方式,否則無法知道參數(shù)列表的結(jié)尾。例如,你可以使第一個(gè)參數(shù)是參數(shù)數(shù)量的計(jì)數(shù)。或者,在你有一組指針的情況下,你可能需要最后一個(gè)指針是 nullptr。有許多方法,但它們都對(duì)程序員來說是繁瑣的。
下面的示例演示了調(diào)用者在第一個(gè)命名參數(shù)中指定提供了多少個(gè)參數(shù)的技術(shù)。該函數(shù)接受任意數(shù)量的 int 并打印出來:
void printInts(size_t num, ...) { va_list ap; va_start(ap, num); for (size_t i { 0 }; i < num; ++i) { int temp { va_arg(ap, int) }; cout << temp << " "; } va_end(ap); cout << endl;}
你可以按以下方式調(diào)用 printInts()。請(qǐng)注意,第一個(gè)參數(shù)指定將跟隨多少個(gè)整數(shù)。
printInts(5, 5, 4, 3, 2, 1);
使用 C 風(fēng)格的變長(zhǎng)參數(shù)列表訪問參數(shù)并不安全。這種方法存在幾個(gè)風(fēng)險(xiǎn),從 printInts() 函數(shù)可以看出:
警告:避免使用 C 風(fēng)格的變長(zhǎng)參數(shù)列表。建議傳遞一個(gè) std::array 或 vector 的值、使用初始化列表,或者使用類型安全的變參模板來實(shí)現(xiàn)變長(zhǎng)參數(shù)列表。
本文鏈接:http://www.www897cc.com/showinfo-26-38135-0.htmlC 語言變長(zhǎng)參數(shù)及其陷阱
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
下一篇: 三分鐘搞懂CUDA和GPU編程