本篇內(nèi)容主要講解“C++怎么生成格式化的標準字符串”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“C++怎么生成格式化的標準字符串”吧!
創(chuàng)新互聯(lián)建站是一家集網(wǎng)站建設(shè),開福企業(yè)網(wǎng)站建設(shè),開福品牌網(wǎng)站建設(shè),網(wǎng)站定制,開福網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,開福網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。兩種格式化字符串方法
眾所周知,C++的std::string
功能殘缺,各種功能都沒有,比如格式化字符串功能。
在python3中,支持兩種格式化字符串的方法,一種是C風(fēng)格,格式化的部分用%開頭,%后面的對應(yīng)具體類型(比如%s對應(yīng)字符串%d對應(yīng)整型),另一種則是類型無關(guān)的風(fēng)格,{0}對應(yīng)第1個參數(shù),{1}對應(yīng)第2個參數(shù)。
>>> "{0}'s age is {1}".format("赤紅", 11)"赤紅's age is 11">>> "%s's age is %d" % ("赤紅", 11)"赤紅's age is 11"
而在C++中則只能借用C函數(shù),用snprintf來格式化一片緩沖區(qū)
#define BUFFSIZE 512 char buf[BUFFSIZE]; snprintf(buf, BUFFSIZE, "%s's age is %d\n", "赤紅", 11);
亦或者用類型無關(guān)的流運算符
std::ostringstream os; os << "赤紅" << "'s age is " << 11 << "\n"; std::string s = os.str();
暫且不談效率問題,這種用<<拼接多個不同類型對象的做法代碼量較大,而且在控制具體輸出格式時更為麻煩,比如控制數(shù)字所占位數(shù),或者小數(shù)點后位數(shù)。至少繁雜得讓我總是記不起來,寧可使用C風(fēng)格snprintf來控制。比如
double d = 3.1415926; snprintf(buf, BUFFSIZE, "圓周率: %-8.3lf是祖沖之發(fā)現(xiàn)的\n", d);
$ ./a.out 圓周率: 3.142 是祖沖之發(fā)現(xiàn)的
通過%-8.3lf將lf(long float即double)類型的浮點數(shù)設(shè)置占位數(shù)為8,設(shè)置小數(shù)點后位數(shù)為3,負號表示左對齊,這種表示方法非常簡單緊湊。
至于用C++的iomanip頭文件實現(xiàn),我還花了點時間查文檔。
double d = 3.1415926; os << "圓周率: " << std::setw(8) << std::fixed << std::setprecision(3) << std::left << d << "是祖沖之發(fā)現(xiàn)的\n";
除了代碼如此之長以及有可能漏掉std::fixed
外,還有問題在于setprecision已經(jīng)改變了默認設(shè)置,也就是說,如果再os <<傳入一個浮點數(shù),保留的小數(shù)點位數(shù)仍然是3位。
也許有人說,這種好處在于setprecision和setw接收的可以是一個變量而非常量。實際上snprintf一樣可以做到。
double d = 3.1415926; int n1 = 8, n2 = 3; snprintf(buf, BUFFSIZE, "圓周率: %-*.*lf是祖沖之發(fā)現(xiàn)的\n", n1, n2, d);
C++包裝snprintf生成格式化的std::string對象
在APUE UNP TLPI這幾本講Linux下C編程的書中,都自己寫了錯誤處理庫來包裝snprintf產(chǎn)生格式化的輸出,以免每次重復(fù)定義緩沖區(qū)/調(diào)用snprintf等等。
這樣的做法有個缺陷就是緩沖區(qū)(字符數(shù)組)長度有限制,當(dāng)然一般而言buffer size定義得足夠大的話是足夠的,畢竟打印太長的格式化字符串不如多調(diào)用幾次函數(shù)。
另一方面,由于這些函數(shù)僅僅是打印信息,尤其是經(jīng)常打印信息后直接退出程序。所以不會返回錯誤字符串。如果在C++中想要把錯誤信息作為異常傳給上一層處理,這些函數(shù)是不夠的。因此需要簡單修改下。
inline std::string format_string(const char* format, va_list args) { constexpr size_t oldlen = BUFSIZ; char buffer[oldlen]; // 默認棧上的緩沖區(qū) va_list argscopy; va_copy(argscopy, args); size_t newlen = vsnprintf(&buffer[0], oldlen, format, args) + 1; newlen++; // 算上終止符'' if (newlen > oldlen) { // 默認緩沖區(qū)不夠大,從堆上分配 std::vector<char> newbuffer(newlen); vsnprintf(newbuffer.data(), newlen, format, argscopy); return newbuffer.data(); } return buffer;}inline std::string format_string(const char* format, ...) { va_list args; va_start(args, format); auto s = format_string(format, args); va_end(args); return s;}
這是模仿UNP的實現(xiàn),定義形參為va_list和...的兩個版本,其中接受va_list的版本還可為其它函數(shù)所用。因為C風(fēng)格的可變參數(shù)列表...不能作為參數(shù)傳遞。另一點,va_list類型也不一定有拷貝構(gòu)造函數(shù),因此得用va_copy來拷貝一份va_list,以供第二次使用。
C++11新增了可變模板參數(shù)特性,使得上述代碼可以得到簡化
template <typename ...Args>inline std::string format_string(const char* format, Args... args) { constexpr size_t oldlen = BUFSIZ; char buffer[oldlen]; // 默認棧上的緩沖區(qū) size_t newlen = snprintf(&buffer[0], oldlen, format, args...); newlen++; // 算上終止符'' if (newlen > oldlen) { // 默認緩沖區(qū)不夠大,從堆上分配 std::vector<char> newbuffer(newlen); snprintf(newbuffer.data(), newlen, format, args...); return std::string(newbuffer.data()); } return buffer;}
而傳遞可變模板參數(shù)也變得十分容易(使用forward完美轉(zhuǎn)發(fā)),示例代碼如下
xyz@ubuntu:~/unp_practice/lib$ cat test.cc #include <string.h>#include <unistd.h>#include "format_string.h"template <typename ...Args>void errExit(const char* format, Args... args) { auto errmsg = format_string(format, std::forward<Args>(args)...); errmsg = errmsg + ": " + strerror(errno) + "\n"; fputs(errmsg.c_str(), stderr); exit(1);}int main() { const char* s = "hello world!"; int fd = -1; if (write(fd, s, strlen(s)) == -1) errExit("write \"%s\" to file descriptor(%d) failed", s, fd); return 0;}xyz@ubuntu:~/unp_practice/lib$ g++ test.cc -std=c++11xyz@ubuntu:~/unp_practice/lib$ ./a.out write "hello world!" to file descriptor(-1) failed: Bad file descriptor
到此,相信大家對“C++怎么生成格式化的標準字符串”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)建站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
網(wǎng)頁標題:C++怎么生成格式化的標準字符串-創(chuàng)新互聯(lián)
文章分享:http://m.rwnh.cn/article12/cejcgc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、Google、網(wǎng)頁設(shè)計公司、網(wǎng)站建設(shè)、定制開發(fā)、自適應(yīng)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容