程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++ 工程實踐(3):采用有利於版本管理的代碼格式

C++ 工程實踐(3):采用有利於版本管理的代碼格式

編輯:C++入門知識

 陳碩 (giantchen_AT_gmail)

Blog.csdn.net/Solstice

版本管理(version controlling)是每個程序員的基本技能,C++ 程序員也不例外。版本管理的基本功能之一是追蹤代碼變化,讓你能清楚地知道代碼是如何一步步變成現在的這個樣子,以及每次 check-in 都具體改動了哪些內部。無論是傳統的集中式版本管理工具,如 Subversion,還是新型的分布式管理工具,如 Git/Hg,比較兩個版本(revision)的差異都是其基本功能,即俗稱“做一下 diff”。

diff 的輸出是個窺孔(peephole),它的上下文有限(diff –u 默認顯示前後 3 行)。在做 code review 的時候,如果能憑這“一孔之見”就能發現代碼改動有問題,那就再好也不過了。

C 和 C++ 都是自由格式的語言,代碼中的換行符被當做 white space 來對待。(當然,我們說的是預處理(preprocess)之後的情況)。對編譯器來說一模一樣的代碼可以有多種寫法,比如

foo(1, 2, 3, 4);

foo(1,

    2,

    3,

    4);

詞法分析的結果是一樣的,語意也完全一樣。

對人來說,這兩種寫法讀起來不一樣,對與版本管理工具來說,同樣功能的修改造成的差異(diff)也往往不一樣。所謂“有利於版本管理”,就是指在代碼中合理使用換行符,對 diff 工具友好,讓 diff 的結果清晰明了地表達代碼的改動。(diff 一般以行為單位,也可以以單詞為單位,本文只考慮最常見的 diff by lines。)

這裡舉一些例子。

對 diff 友好的代碼格式
1. 多行注釋也用 //,不用 /* */
Scott Meyers 寫的《Effective C++》第二版第 4 條建議使用 C++ 風格,我這裡為他補充一條理由:對 diff 友好。比如,我要注釋一大段代碼(其實這不是個好的做法,但是在實踐中有時會遇到),如果用 /* */,那麼得到的 diff 是:

diff --git a/examples/asio/tutorial/timer5/timer.cc b/examples/asio/tutorial/timer5/timer.cc
--- a/examples/asio/tutorial/timer5/timer.cc
+++ b/examples/asio/tutorial/timer5/timer.cc
@@ -18,6 +18,7 @@ class Printer : boost::noncopyable
     loop2_->runAfter(1, boost::bind(&Printer::print2, this));
   }
+  /*
   ~Printer()
   {
     std::cout << "Final count is " << count_ << " ";
@@ -38,6 +39,7 @@ class Printer : boost::noncopyable
       loop1_->quit();
     }
   }
+  */
   void print2()
   {從這樣的 diff output 能看出注釋了哪些代碼嗎?

如果用 //,結果會清晰很多:

diff --git a/examples/asio/tutorial/timer5/timer.cc b/examples/asio/tutorial/timer5/timer.cc
--- a/examples/asio/tutorial/timer5/timer.cc
+++ b/examples/asio/tutorial/timer5/timer.cc
@@ -18,26 +18,26 @@ class Printer : boost::noncopyable
     loop2_->runAfter(1, boost::bind(&Printer::print2, this));
   }
-  ~Printer()
-  {
-    std::cout << "Final count is " << count_ << " ";
-  }
+  // ~Printer()
+  // {
+  //   std::cout << "Final count is " << count_ << " ";
+  // }
-  void print1()
-  {
-    muduo::MutexLockGuard lock(mutex_);
-    if (count_ < 10)
-    {
-      std::cout << "Timer 1: " << count_ << " ";
-      ++count_;
-
-      loop1_->runAfter(1, boost::bind(&Printer::print1, this));
-    }
-    else
-    {
-      loop1_->quit();
-    }
-  }
+  // void print1()
+  // {
+  //   muduo::MutexLockGuard lock(mutex_);
+  //   if (count_ < 10)
+  //   {
+  //     std::cout << "Timer 1: " << count_ << " ";
+  //     ++count_;
+  //
+  //     loop1_->runAfter(1, boost::bind(&Printer::print1, this));
+  //   }
+  //   else
+  //   {
+  //     loop1_->quit();
+  //   }
+  // }
   void print2()
   {同樣的道理,取消注釋的時候 // 也比 /* */ 更清晰。

另外,如果用 /* */ 來做多行注釋,從 diff 不一定能看出來你是在修改代碼還是修改注釋。比如以下 diff 似乎修改了 muduo::EventLoop::runAfter 的調用參數:

diff --git a/examples/asio/tutorial/timer5/timer.cc b/examples/asio/tutorial/timer5/timer.cc
--- a/examples/asio/tutorial/timer5/timer.cc
+++ b/examples/asio/tutorial/timer5/timer.cc
@@ -32,7 +32,7 @@ class Printer : boost::noncopyable
       std::cout << "Timer 1: " << count_ << " ";
       ++count_;
-      loop1_->runAfter(1, boost::bind(&Printer::print1, this));
+      loop1_->runAfter(2, boost::bind(&Printer::print1, this));
     }
     else
     {其實這個修改發生在注釋裡邊 (要增加上下文才能看到, diff -U 20,多一道手續,降低了工作效率),對代碼行為沒有影響:

diff --git a/examples/asio/tutorial/timer5/timer.cc b/examples/asio/tutorial/timer5/timer.cc
--- a/examples/asio/tutorial/timer5/timer.cc
+++ b/examples/asio/tutorial/timer5/timer.cc
@@ -20,31 +20,31 @@ class Printer : boost::noncopyable
   /*
   ~Printer()
   {
     std::cout << "Final count is " << count_ << " ";
   }

   void print1()
   {
     muduo::MutexLockGuard lock(mutex_);
     if (count_ < 10)
     {
       std::cout << "Timer 1: " << count_ << " ";
       ++count_;
-      loop1_->runAfter(1, boost::bind(&Printer::print1, this));
+      loop1_->runAfter(2, boost::bind(&Printer::print1, this));
     }
     else
     {
       loop1_->quit();
     }
   }
   */
   void print2()
   {
     muduo::MutexLockGuard lock(mutex_);
     if (count_ < 10)
     {
       std::cout << "Timer 2: " << count_ << " ";
       ++count_;總之,不要用 /* */ 來注釋多行代碼。

或許是時過境遷,大家都在用 // 注釋了,《Effective C++》第三版去掉了這一條建議。

2. 局部變量與成員變量的定義
基本原則是,一行代碼只定義一個變量,比如

double x;

double y;

將來代碼增加一個 double z 的時候,diff 輸出一眼就能看出改了什麼:

@@ -63,6 +63,7 @@ private:
   int count_;
   double x;
   double y;
+  double z;
 };

 int main()如果把 x 和 y 寫在一行,diff 的輸出就得多看幾眼才知道。

@@ -61,7 +61,7 @@ private:
   muduo::net::EventLoop* loop1_;
   muduo::net::EventLoop* loop2_;
   int count_;
-  double x, y;
+  double x, y, z;
 };

 int main()所以,一行只定義一個變量更利於版本管理。同樣的道理適用於 enum 成員的定義,數組的初始化列表等等。

3. 函數聲明中的參數
如果函數的參數大於 3 個,那麼在逗號後面換行,這樣每個參數占一行,便於 diff。以 muduo::net::TcpClient 為例:

class TcpClient : boost::noncopyable
{
 public:
  TcpClient(EventLo

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved