C++產品中常用的3個開源項目 | 第101期

C++大概是一種會讓很多程序員都頭疼的編程語言,其複雜的語法和笨拙的內存管理機制讓產品很容易出現各種意想不到的BUG。現在還在用C++開發產品大概只有兩種原因:(1) 只會C++,(2) 計算性能要求高。無論是第一種原因,還是第二種原因,都讓你不得不直接面對C++,那麼有沒有什麼巨人的肩膀可以踮踮腳呢?這裡不得不提起谷歌推出的三個經典開源項目:gflags、glog和gtest。

1. GFlags

從命令行傳入一些參數來控制程序運行的流程和效果是一個比較普遍的需求,開源社區也有很多的解決方案,這裡推薦使用GFlags。這個開源庫可以讓你在你的產品中很容易地加入命令行參數定義:

<code>DEFINE_int32(arg, 

val

,

"introduct"

);/<code>

這樣,你就定義了一個名為 “FLAGS_arg” 的 int 全局變量用於接受命令行傳入的 “arg” 參數,並且設置了默認值為 “val”。

隨便編寫一個普通的main函數沒有辦法完成從命令行到FLAGS_arg的參數傳遞,我們需要在main函數中調用命令行參數解析的接口:

<code>

int

main

(

int

argc,

char

** argv)

{ gflags::ParseCommandLineFlags(&argc, &argv,

true

);

std

::

cout

<< FLAGS_arg <

std

::

endl

;

return

0

; }/<code>

GFlags的使用是不是非常簡單!如果你在自己的產品中遇到較多的參數配置,並且不勝其煩,那麼不妨試試GFlags。

C++產品中常用的3個開源項目 | 第101期

GFlags

2. Glog

一個成熟的軟件產品無論如何都無法缺少日誌系統,而一個不成熟的軟件就更需日誌了,因為隨時產生的“不符合預期”情況都需要找到原因,並進行修正。很難想象在一個龐大複雜的軟件工程中,沒有記錄運行狀況的日誌。有些對debug模式情有獨鍾的朋友可能認為日誌是多此一舉,但實際的開發經驗表明了,在軟件產品中,使用日誌的分析效率遠高於debug模式。因此,不到萬不得已,絕不使用debug。

開源社區中提供的日誌項目也很多,有些朋友或許還有自己使用文件操作打印日誌的習慣,這裡推薦一款谷歌的開源日誌項目Glog。日誌系統並不像大家通常想象的那樣只是把字符串寫入文件那麼簡單,因為程序運行的情況有時會非常複雜,比如多線程運行;有時會對日誌系統的性能有要求,還會有對日誌類型和格式的要求等等。使用一款經過驗證的成熟日誌系統,能夠避免很多不必要的踩坑經歷,而且也有更多的網上資源可供查詢。

日誌系統往往需要在程序啟動的時候進行初始化,glog的初始化可以參照如下例子實現:

<code> 

int

main

(

int

argc,

char

** argv)

{ google::InitGoogleLogging(argv[

0

]);

return

0

; }/<code>

glog提供瞭如下級別的日誌:INFO、WARNING、ERROR、以及FATAL,其中FATAL級別的日誌一旦打印,程序就會終止。開發者可以使用以下的宏來進行日誌的打印:

<code>

LOG

(INFO) <

"hello"

;/<code>

如果你需要打印一些僅僅在debug模式下生效的日誌,可以使用 DLOG 宏。如果你還有很多自定義的級別,那麼可以使用 VLOG 宏,不過需要記住, VLOG 的數值越低級別越高。

關於Glog更多的個性化配置可以參照官方的手冊,不過有一些問題手冊是不會告訴你的,比如:

<code>(1) 每一行日誌最多隻能打印30000個字符
(2) 日誌文件的名字非常不靈活,每次運行都產生一個新的日誌文件/<code> 

如果你對以上這兩個問題強烈不滿,那麼可能需要稍加修改一下glog的源代碼。

C++產品中常用的3個開源項目 | 第101期

GLog

3. GTest

測試常常被一些經驗尚淺的開發者所輕視,卻不知這是能夠保證穩定性、避免低級錯誤的最有效的方法。無論是大公司還是小公司,日常的開發都是很慌忙的,代碼也常常是在頭暈腦脹的情況下寫出來的。這種現實環境之下,如果缺少對應的測試,輕則浪費很多時間用於調試bug,重則造成軟件產品出現嚴重不穩定的錯誤。谷歌開源的GTest項目就是業內常用的一款開源的C++單元測試項目。

使用GTest首先需要包含對應的頭文件 "gtest/gtest.h"。如果你已經編寫了一個函數 func(),那麼可以創建如下單元測試:

<code>TEST(MyFuncs, FuncRet) {
    EXPECT_TRUE(

func

()

== 0);

}/<code>

以上例子用於進行單個函數的功能測試,如果某個函數有多個邊界條件,可以使用 TEST 宏定義多個單元測試。

如果你需要測試一個類,並且還需要在測試之間預備一些環境,那麼就需要稍微複雜一點。首先,編寫一個類,並繼承 testing::Test;然後是按需要實現一些成員,比如 SetUpTestCase 和 TearDownTestCase 用於在這個類的所有測試之前和之後運行,常用於加載環境和釋放資源,比如 SetUp 和 TearDown 用於在這個類的每一個單元測試之前和之後運行。

日常使用GTest組織單元測試並不需要知道那些複雜的用法,先用起來,排除軟件中存在的隱患,至於那些神乎其技的東西可能這輩子都用不上,就不需要費心思去關心了。

C++產品中常用的3個開源項目 | 第101期

GTest

以上這三個開源項目都是經過很多大公司的產品線驗證過的,在自己的項目或者產品中使用這些開源代碼也就放心得多。萬一遇上搞不定的情況,可以在網上搜索到海量的解決方案;如果現有情況無法滿足需要,還可以在這些開源項目的基礎上進行開發。


分享到:


相關文章: