欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++生成格式化的標準字符串實例代碼

 更新時間:2019年09月10日 14:50:10   作者:哈莉_奎茵  
這篇文章主要給大家介紹了關(guān)于C++生成格式化的標準字符串的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

兩種格式化字符串方法

眾所周知,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++; // 算上終止符'\0'
 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++; // 算上終止符'\0'

  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++11
xyz@ubuntu:~/unp_practice/lib$ ./a.out 
write "hello world!" to file descriptor(-1) failed: Bad file descriptor

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • C++中new和delete的使用方法詳解

    C++中new和delete的使用方法詳解

    這篇文章主要介紹了C++中new和delete的使用方法詳解的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • 詳解C++異常處理機制示例介紹

    詳解C++異常處理機制示例介紹

    任何東西都可以認為是異常,錯誤只是異常的一種。本文將帶大家了解C++中異常是什么,是如何捕獲和處理的等相關(guān)知識。文中示例代碼簡潔易懂,感興趣的小伙伴可以了解一下
    2022-08-08
  • C++常用語句簡介

    C++常用語句簡介

    這篇文章主要介紹了C++常用語句簡介,文章將要介紹的常用語句有聲明變量、賦值語句、cin、cout語句、庫函數(shù)、自定義函數(shù),需要的朋友可以參考一下,希望對你有所幫助
    2021-11-11
  • C語言實現(xiàn)自定義掃雷游戲(遞歸版)

    C語言實現(xiàn)自定義掃雷游戲(遞歸版)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)自定義掃雷游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語言使用ffmpeg和sdl實現(xiàn)多路音頻播放

    C語言使用ffmpeg和sdl實現(xiàn)多路音頻播放

    這篇文章主要為大家詳細介紹了一種基于ffmpeg和sdl實現(xiàn)的音頻多路混合的方法,文中的示例代碼講解詳細,感興趣的小伙伴可以參考一下
    2023-06-06
  • Gstreamer基礎(chǔ)知識教程

    Gstreamer基礎(chǔ)知識教程

    由于deepstream是基于gstreamer的,所以要想在deepstream上做拓展,需要對gstreamer有一定的認識,以下主要介紹Gstreamer整體框架和Gstreamer基礎(chǔ)概念,需要的朋友可以參考下
    2022-07-07
  • C語言實現(xiàn)ATM機存取款系統(tǒng)

    C語言實現(xiàn)ATM機存取款系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)ATM機存取款系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C語言內(nèi)存泄漏常見情況及解決方案詳解

    C語言內(nèi)存泄漏常見情況及解決方案詳解

    這篇文章主要為大家介紹了C語言內(nèi)存泄漏常見情況及解決方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • C語言 數(shù)據(jù)結(jié)構(gòu)中求解迷宮問題實現(xiàn)方法

    C語言 數(shù)據(jù)結(jié)構(gòu)中求解迷宮問題實現(xiàn)方法

    這篇文章主要介紹了C語言 數(shù)據(jù)結(jié)構(gòu)中求解迷宮問題實現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 簡單分析針對ARM平臺的C語言程序的編譯問題

    簡單分析針對ARM平臺的C語言程序的編譯問題

    這篇文章主要介紹了針對ARM平臺的C語言程序的編譯問題,從優(yōu)化編譯選項的幾個方面進行分析,需要的朋友可以參考下
    2015-12-12

最新評論