91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++怎么生成格式化的標準字符串

發布時間:2021-09-14 22:21:05 來源:億速云 閱讀:111 作者:chen 欄目:編程語言

本篇內容主要講解“C++怎么生成格式化的標準字符串”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“C++怎么生成格式化的標準字符串”吧!

兩種格式化字符串方法

眾所周知,C++的std::string功能殘缺,各種功能都沒有,比如格式化字符串功能。

在python3中,支持兩種格式化字符串的方法,一種是C風格,格式化的部分用%開頭,%后面的對應具體類型(比如%s對應字符串%d對應整型),另一種則是類型無關的風格,{0}對應第1個參數,{1}對應第2個參數。

>>> "{0}'s age is {1}".format("赤紅", 11)"赤紅's age is 11">>> "%s's age is %d" % ("赤紅", 11)"赤紅's age is 11"

而在C++中則只能借用C函數,用snprintf來格式化一片緩沖區

#define BUFFSIZE 512 char buf[BUFFSIZE]; snprintf(buf, BUFFSIZE, "%s's age is %d\n", "赤紅", 11);

亦或者用類型無關的流運算符

std::ostringstream os; os << "赤紅" << "'s age is " << 11 << "\n"; std::string s = os.str();

暫且不談效率問題,這種用<<拼接多個不同類型對象的做法代碼量較大,而且在控制具體輸出格式時更為麻煩,比如控制數字所占位數,或者小數點后位數。至少繁雜得讓我總是記不起來,寧可使用C風格snprintf來控制。比如

double d = 3.1415926; snprintf(buf, BUFFSIZE, "圓周率: %-8.3lf是祖沖之發現的\n", d);

$ ./a.out 圓周率: 3.142 是祖沖之發現的

通過%-8.3lf將lf(long float即double)類型的浮點數設置占位數為8,設置小數點后位數為3,負號表示左對齊,這種表示方法非常簡單緊湊。

至于用C++的iomanip頭文件實現,我還花了點時間查文檔。

double d = 3.1415926; os << "圓周率: " << std::setw(8) << std::fixed  << std::setprecision(3) << std::left  << d << "是祖沖之發現的\n";

除了代碼如此之長以及有可能漏掉std::fixed外,還有問題在于setprecision已經改變了默認設置,也就是說,如果再os <<傳入一個浮點數,保留的小數點位數仍然是3位。

也許有人說,這種好處在于setprecision和setw接收的可以是一個變量而非常量。實際上snprintf一樣可以做到。

double d = 3.1415926; int n1 = 8, n2 = 3; snprintf(buf, BUFFSIZE, "圓周率: %-*.*lf是祖沖之發現的\n", n1, n2, d);

C++包裝snprintf生成格式化的std::string對象

在APUE UNP TLPI這幾本講Linux下C編程的書中,都自己寫了錯誤處理庫來包裝snprintf產生格式化的輸出,以免每次重復定義緩沖區/調用snprintf等等。

這樣的做法有個缺陷就是緩沖區(字符數組)長度有限制,當然一般而言buffer size定義得足夠大的話是足夠的,畢竟打印太長的格式化字符串不如多調用幾次函數。

另一方面,由于這些函數僅僅是打印信息,尤其是經常打印信息后直接退出程序。所以不會返回錯誤字符串。如果在C++中想要把錯誤信息作為異常傳給上一層處理,這些函數是不夠的。因此需要簡單修改下。

inline std::string format_string(const char* format, va_list args) { constexpr size_t oldlen = BUFSIZ; char buffer[oldlen]; // 默認棧上的緩沖區 va_list argscopy; va_copy(argscopy, args); size_t newlen = vsnprintf(&buffer[0], oldlen, format, args) + 1; newlen++; // 算上終止符'' if (newlen > oldlen) { // 默認緩沖區不夠大,從堆上分配  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的實現,定義形參為va_list和...的兩個版本,其中接受va_list的版本還可為其它函數所用。因為C風格的可變參數列表...不能作為參數傳遞。另一點,va_list類型也不一定有拷貝構造函數,因此得用va_copy來拷貝一份va_list,以供第二次使用。

C++11新增了可變模板參數特性,使得上述代碼可以得到簡化

template <typename ...Args>inline std::string format_string(const char* format, Args... args) {  constexpr size_t oldlen = BUFSIZ;  char buffer[oldlen]; // 默認棧上的緩沖區  size_t newlen = snprintf(&buffer[0], oldlen, format, args...);  newlen++; // 算上終止符''  if (newlen > oldlen) { // 默認緩沖區不夠大,從堆上分配    std::vector<char> newbuffer(newlen);    snprintf(newbuffer.data(), newlen, format, args...);    return std::string(newbuffer.data());  }  return buffer;}

而傳遞可變模板參數也變得十分容易(使用forward完美轉發),示例代碼如下

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++怎么生成格式化的標準字符串”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

仙游县| 高青县| 体育| 德清县| 从化市| 金溪县| 聊城市| 黔西| 阿坝县| 华蓥市| 宁化县| 正宁县| 广饶县| 赤城县| 余干县| 泾源县| 克什克腾旗| 沾化县| 平顶山市| 当雄县| 吉木乃县| 苏尼特右旗| 中山市| 镇康县| 江安县| 布拖县| 尼木县| 射洪县| 广南县| 丰城市| 乾安县| 军事| 宜昌市| 嘉兴市| 中宁县| 永修县| 龙胜| 清远市| 威远县| 高碑店市| 垦利县|