Powered by and 圖示來源
顯示具有 程式 標籤的文章。 顯示所有文章
顯示具有 程式 標籤的文章。 顯示所有文章

2011年12月25日 星期日

這學期的數位視訊系統老師叫我們寫一個作業,題目:
是說把一張彩色的圖以RBG為做向量(vector),再透過generalized Lloyd algorithm去把圖片重新編碼。

大學時都沒這麼認真用過MATLAB! @@

glloyd_training.m
function [codebook, Index] = glloyd_training(ImgPxl, CS, Vector_Len, er, x, y)
  Training_idx = (x*y*3)/Vector_Len ;
  Training_set = reshape(ImgPxl(:), Training_idx, Vector_Len);
  codebook = zeros(CS, Vector_Len) ;

  Child_group = fix(Training_idx/CS); %每個codebook 值將會代表幾個原始值,取整數
  for i = 1 : CS %先分成codesize 區塊,每一塊先取平均值
    codebook(i,:) = mean(Training_set(((i-1)*Child_group+1):i*Child_group,:) );
  end

  old_MSE = 0;
  inited=0;

  MSE_diff=100;
  min_diff =2;
  %新舊codebook 的MSE相差小於min_diff,就不再做下去. 當作是完成了.
  while (MSE_diff>min_diff)
    if (inited>0)
      for i = 1 : CS
        same_group = find(Index == i) ;
        if ~isempty(same_group)
          codebook(i, :) = mean(Training_set(same_group, :));
        else %沒有任何值落在這邊 就抓附近的來補一下
          if i == 1
            codebook(i,:) = mean(codebook([2 3],:)) ;
          elseif i == CS
            codebook(i,:) = mean(codebook([CS-1 CS-2],:)) ;
          else
            codebook(i,:) = mean(codebook([i+1 i-1],:)) ;
          end
        end
      end
    else
      inited =1;
    end

  coded_value = zeros(Training_idx,1);
  %將所有的vector 依codebook分類
  for i = 1 : Training_idx
    Current_Vector = Training_set(i,:);
    %分身為CS筆
    Current_Vector_n = Current_Vector(ones(CS,1),:);
    %算出MSE
    vector_MSE = sum(((Current_Vector_n-codebook).^2).')/Vector_Len ;
    %選MSE最小的
    [coded_value(i), Index(i)] = min(vector_MSE) ;
  end

  VQImg = codebook(Index,:) ;
  VQImg = reshape(VQImg(:), y, x, 3) ;
  MSE = mse(ImgPxl - VQImg);

  if (old_MSE)
    MSE_diff = abs(old_MSE-MSE);
  else
    MSE_diff = abs(MSE);
  end
    old_MSE= MSE;
    MSE_diff
  end
廣告



VQ.m
function VQ(CS)
%Usage: VQ(CS)
%CS is codebook size(L)
    Vector_Len = 3;
    er = 5;
    ImgFile = 'Lena.jpg';

    ImgPxl = double(imread(ImgFile)) ;
    Pic_info = imfinfo(ImgFile);

    [codebook, index] = glloyd_training(ImgPxl, CS, Vector_Len, er, Pic_info.Width, Pic_info.Height) ;

    VQImg = codebook(index,:) ;

    VQImg = reshape(VQImg(:), Pic_info.Height, Pic_info.Width, 3) ;
    MSE = mse(ImgPxl - VQImg)

    index = gcf();
    if (index ==1)
    figure(index);
        imshow(uint8(ImgPxl)) ;
        title('Source' ) ;
    end
    figure(index+1) ;
    imshow(uint8(VQImg)) ;
    title(['VQ L=',int2str(CS)] );

檔名在VQ.m是寫死的
ImgFile = 'Lena.jpg';

把程試簡化,讓助教比較好處理。
>> help VQ
Usage: VQ(CS)
CS is codebook size(L)

跑幾張圖來試試看好了!

source
廣告




VQ(8)

VQ(32)

VQ(128)

居然V32就已經看不太出來有什麼差別了.
這個故事告訴我們,"做影像處理的報告,乖乖的用Lenna就對了"

matlab code參考自:
http://www.wretch.cc/blog/Lak4CYUT/3518815


2009年5月3日 星期日

網路上查了一輪...基本上這個ibdata1 (路徑為 /var/lib/mysql/ibdata1),是一個只會長大不會變小的檔案它是mysql的bug.. 在bug還沒解之前,想要縮小有個辦法.

1.導出資料庫數據
2.砍掉重練
3.導入第1步時的數據


細部分解:
1.先備份整個資料庫(怕死)
cd /var/lib/
service mysqld stop
tar -zcvf mysql.tgz mysql
service mysqld start


2.停止服務(也是怕死), 假如db是專給web那麼...
service httpd stop

3.把資料庫的資料導出, 自己有什麼資料自己最清楚, 一個一個拉出來囉
mysqldump --lock-all-tables -u root -p 資料庫名稱 > example.sql

4.導出之後, 會有很多個.sql, 這時提起勇氣...
rm /var/lib/mysql/ibdata1

5.資料庫一個一個導回去
mysql -u root -p 資料庫名稱 < example.sql

6.開啟服務, 仍以web 為例.
service httpd start

7.測試....
成功是一定的,但天有不測風雲, 資料如果不見,至少還有mysql.tgz頂著
廣告



參考資料:
原文

MySQL Server 的日常維護中最重要的一項大概就是資料庫的定時備份,而 MySQL 資料庫的備份方式有很多但一般來說大致上可概分為二種:

1. Binary Copy (直接複製資料庫檔案)
2. Dump Database (將資料庫輸出成為文字檔)




一、Binary Copy (直接複製資料庫檔案)

開門見山的說,非常不建議你這樣子做。MySQL 支援許多種不同的 Storage Engine,但並不是每一種 Storage Engine 都是 Binary Portable,意思就是說不是每一種 Storage Engine 都可以讓你把資料庫檔案直接複製到另外一台 MySQL Server,然後還可以正常運作的。MySQL 預設的 MyISAM Storage Engine 是 Binary Portable 的,因此若你的資料庫只有使用 MyISAM Storage Engine 的話,那麼你大可以直接複製資料庫檔案來進行備份(當然還必須考慮到資料的一致性,比方說複製之前先關閉 MySQL Server)。但若您有使用到 InnoDB Storage Engine,那麼你就不能這麼做,因為 InnoDB Storage Engine "不是" Binary Portable,只要 CPU 的浮點運算架構不同,複製過去的資料將無法正常運作。除此之外,你複製起來的 InnoDB 資料庫檔案(share table space)若是還原到不同版本的 MySQL Server 上,也會有很大的機率無法正常運作。除非你很肯定備份(複製)起來的資料只會使用在 "同一台 Server" 並使用 "同一個版本" 的 MySQL Server,不然請勿使用此方法進行備份。

註:

對於 MyISAM Storage Engine,每個資料庫(Database)都是一個獨立的目錄,而資料庫中的資料表則會分別以三個檔案儲存在該目錄中,這三個檔案分別是:

FRM: 儲存這個資料表的結構
MYD: Row Data,也就是你存在資料表(table)裡的資料
MYI: 此資料表的索引

但對於 InnoDB Storage Engine 來說,所有的資料庫(Database)與資料表(Table)都是儲存在同一個(或同一系列)的檔案之中,例如 /var/lib/mysql/ibdata1。



二、Dump Database (將資料庫輸出成為文字檔)


MySQL 在安裝時即有提供一系列的客戶端程式(Client Program),這些程式其實就是各種功能不同的 Perl Scripts 的集合,其中包括有協助您操控 Server 的 mysqladmin、用來執行 SQL 指令的 mysql、轉換 binary log 用的 mysqlbinlog 等等。其中有一樣工具是專門讓您用來備份資料庫的,那就是 mysqldump。

mysqldump 的使用方式十分的簡易,其語法為:
mysqldump --lock-all-tables -u root -p 資料庫名稱 > example.sql

* --lock-all-tables:進行備份時將正在備份的資料庫裡的資料表,全部鎖定以確保資料的一致性
* -u root:使用 root 帳號進行備份
* -p:需要輸入密碼,如果你的 root 帳號有密碼保護,而你又不加這個選項,就會直接 ACCESS DENIED
* 資料庫名稱:你要備份的資料庫名稱
* example.sql:這個部份你想取什麼名字都行,總之這裡就是備份出來的檔案名稱


開啟備份出來的檔案看看,你會發現裡面其實是由許多 SQL 指令所組成,而這些 SQL 指令就是用來重建整個資料庫用的,因此當您還原資料庫的時候其實對 MySQL 來說,只是單純的重新執行備份檔裡面所有的 SQL 指令。由於備份出來的檔案是單純的文字檔案,因此它是 Binary Portable,你可以將它複製到任何一台 MySQL Server 上然後進行還原。

還原的方式也很簡單,只要使用以下的指令即可:
mysql -u root -p 資料庫名稱 < example.sql

大部份論壇程式都會提供資料庫備份機制來協助您備份論壇的資料庫,但除非您無法直接掌控伺服器(例如租用虛擬主機)或是你不具有使用 SHELL 執行指令的權限,否則不建議您使用那些第三方程式所提供的功能來備份資料庫,不然您有可能會遇到備份出來的東西還原不回去的情況。


mysqlcheck -a -c -o -r -A --user=username --password=pwd -> for check


2009年4月9日 星期四

寫程式.. 常常會用一個開關來控制debug message

通常會有幾種寫法。

1.用一個function包起來, 在function中決定訊息流向.

void dbgprint(const char *format, ...)
{
    va_list arg;

    va_start(arg, format);
    vsnprintf(rule_buf+strlen(CMD_NAME), BUF_SIZE, format, arg);
    va_end(arg);

    if(debug)
        fprintf(fw_rule_fp,"%s\n",rule_buf);
}


2.用定義來決定function
#if 0
    #define DBG printk
#else
    #define DBG
#endif


就程式而且,第二個方法速度快而且code size會比較小,除非有什麼其它需要,通常來說會用第二種。

廣告




第二種又有一些變型。 直接把目前覺得最棒的變形記下來。

#if DEBUG
    #define DBG(args...) printk(args)
#else
    #define DBG(args...)
#endif

在Makefie 中
CFLAGS += -DDEBUG


2008年10月28日 星期二

今天我想要抱怨一下他馬的亂搞svn 的人。

首先,不知道什麼是svn的人應該不會有興趣,直接跳過吧~!

正題來了,什麼是svn呢?


Subversion是一個版本控制系統,相對於的RCS、CVS,採用了分支管理系統,它的設計目標就是取代CVS。網際網路上免費的版本控制服務多基於Subversion。

詳情請洽:wiki:svn


2008年9月17日 星期三

忽然,有一個想法。上面google區塊跟aide優選文章區塊有沒有辦法動態變換位置。它們的位置不就是簡單的css float屬性而已嗎?應該很簡單。

所以我就開工了,至於為什麼要想讓它們動態變換位置呢? 最有可能的原因是"太閒"。

在寫javascript的過程中我發現一個問題,那就是CSS的float居然是null,本來就沒有值的東西,我去改它,當然不會動,這個地方有問題。

上網查資料,果然在這邊找到了解法。

想要控制css的float要用:
obj.style.cssFloat = "left";

而不是
obj.style.float = "left";
(一般控制css都是這樣用的,Object.style.屬性= xxx)


就這樣完工了,上面兩個大block會亂數的左右換,如果我把sidebar還有sidebar與本文也這樣做,那麼整個blog就會有8個不同的樣貌。

如果再多寫一些,讓它們換來換去,不知道會變成多樣化還是變成很混亂。


2008年8月12日 星期二

寫玩之後,自己試玩了一下,說真的,不好玩,聲光效果太差了,加上javascipt 沒有delay, wait之類的function,只能用Timer繞路寫出想要的功能,不好寫。

本來預計要寫的功能,應該不會再加上去了,不好玩,沒成就感。 -_- (好像在IE上會有些問題,同樣的圖片會一直上server抓,造成畫面出不來)

=====================遊戲區開始=====================

=====================遊戲區結束=====================


這失敗品就當是在練javascript 跟 data structure了


2008年8月7日 星期四

原文出處

你所想像不到的 JavaScript

原文排版亂掉了,我重新排過。

這不是一篇教你如何在網頁中應用 JavaScript 的教材。
這是一篇讓你明瞭看似簡單的 JavaScript,其實其核心語法功能強大。我將在這篇文章中說明 JavaScript 物件導向的特性,並說明如何透過這些特性,達到傳統程式語言 (C++/Java) 所難以完成的功能。

Written by Edward Hsieh/謝鎮澤 January 04, 2002

Everything is Object in JavaScript
開宗明義:在 JavaScript 中任何東西都是物件:變數是物件、函式是物件,常數也是物件。證明方式:

alert (typeof('abc'));
alert (typeof(123));
var ary = [123, "abc"];
alert (typeof(ary));

上面的 typeof 會顯示物件資料型態。得到結果分別是 string, number, object。

Create Objects in JavaScript
既然任何東西都是物件,那建立物件的方法就多了。直接看個例子:

var main = new Object; // 建立新物件
main.x = 123; // 設定物件成員變數(屬性)之一
main["y"] = "XYZ"; // 設定物件成員變數(屬性)之二
alert(main["x"]); // 取得物件屬性並輸出
alert(main.y);

可以看到在 JavaScript 中,main.x 與 main["x"] 這兩種語法是通用的。其實在其他語言中,這兩種表示法的語意並不相同。我稍後再作說明。

List All Members in an Object
這是 JavaScript 的必殺技,使用 JavaScript 的人務必要學會這個技巧。底下函式可以傳回一個物件的所有成員的字串表達式,包

括物件中的屬性及方法。在物件導向程式設計中,這種技術叫 reflection。

function listMember(main) {
var s = "";
for( key in main ) // 使用 in 運算子列舉所有成員
s += key + ": " + main[key] + "n";
return s;
}

範例碼中的 key 會對應到物件中的屬性名稱,如 "x" 或 "y",而 main[key] 則對應到屬性值。

說這項技巧是必殺技的原因是,你可以透過這項技巧,將物件封裝的黑箱打開來,看看裡面藏有什麼東西。我常用這項技巧來看看

IE 與 Mozilla 的 Dom 物件模型有何不同。試試看下面呼叫範例,就可以知道這項技巧的強大了:

var ary = [123, "abc"];
alert (listMember(ary));
alert (listMember(document.location));

Construct Object with Initial Value
要在建立物件的同時指定物件初始值,必須先透過 function 建立一個「原型物件」(或稱為 constructor),再透過 new 運算子建

立新物件。例如以下程式碼會建立一個二維陣列的原型,再產生一個新的二維物件。

function Array2DVar(x,y) { // 定義二維陣列原型
this.length = x;
this.x = x; // x 維度長度
this.y = y; // y 維度長度
for(var i = 0; i < this.length; i++) // 初始各元素值為 null this[i] = new Array(y); // this 代表物件本身 } var a2dv = new Array2DVar(10, 10); // 建立新的 10*10 的二維陣列 a2dv[1][3] = "ABC"; // 設定二維陣列元素值 a2dv[2][6] = "XYZ"; a2dv[9][9] = 1000; alert( a2dv[1][3]); // 取得二維陣列元素值,並顯示出來 alert( a2dv[2][6]); alert( a2dv[9][9]); Initial Array Object 在 JavaScript 中陣列也是物件 (其實近代多數語言中陣列也都是物件,只有像 C 或 Assembly 這類古老的

語言才不把陣列看成物件),因此也可以用 constructor 的語法來建構。當然 JavaScript 還提供了 [] 語法,以更方便建構陣列,

範例如下:

a = new Array("abc", "xyz", 1000); // constructor 語法,或 a = ["abc", "xyz", 1000]; // 陣列標準語法

陣列的元素可以是簡單的資料、其他物件,或是函數。舉個例子來在陣列裡面放函式:

b = [ // 使用函式作為陣列元素
function () { alert("這個好玩!") }, function () { alert("再按一次離開!") }, function () { alert("再來一次!") }, function () { alert("最後一次!") } ];

for (var i = 0; i < b.length ; i++) b[i](); 最後一個 for 迴圈是個有趣的應用。由於 b 陣列中現在存放的所有元素都是函式,因此我們可以對 b 的每個元素進行呼叫。 Object as Association Array
關連陣列 (Assocation Array) 又稱作 Map 或 Dictionary,是一種物件容器,其中可以放置許多的 key-value pair,以存取子物

件。在JavaScript 中,物件本身就可以作為關連陣列。以關連陣列的方式初始化物件的範例如下:

obj1 = {"a" : "Athens" , "b" : "Belgrade", "c" : "Cairo"};
alert(obj1["a"]); // 顯示 Athens
obj2 = { name: "Edward", showName: function() { alert(this.name); } // 使用函式作為物件屬性 }
obj2.showName(); // 顯示 Edward obj2.age = 23; // 屬性可以動態加入

其 中 obj1 儲存了三個子元素,其鍵 (key) 為 "a", "b" 與 "c",而值 (value) 為 "Athens", "Belgrade" 與 "Cairo"。obj2 中

showName 鍵所對應的值為 function,因此 obj2.showName() 即為函式呼叫。

Object as Return Value
雖然 Javascript 的函式只能傳回一個變數,但您卻可以將傳回值設定為物件,達到傳回 1個以上變數值的效果

function a () { return [32, 17]; }
b = a();
alert( b ); // 或 alert(a());

function pixel () { return {"x": 32, "y":17}; }
point = pixel ();
alert (point.x + "n" + point.y); // 或 alert (pixel().x + "n" + pixel().y);

Delegation Function Object
函式也是物件,只是其中包含的是程式的邏輯。這項特性可拿來作為委任式的程式設計,亦即使用委任函式當作另一函式的參數:

function doloop(begin, end, func) { // 這個函式是個 iterator
for (var i = begin; i < end; i++) { func(i); } } function func1(i) { // 印出 ** n ** document.writeln("** " + i + " ** "); } doloop(1, 10, func1); // 印出 1o 行 ** n ** doloop(20, 29, function(i) {document.writeln("## " + i + " ## "); }); Object = Properties + Behaviors
古有明訓:程式 = 資料結構 + 演算法。而物件是建構程式的基本單位,自然的具有相同的性質。物件除了有屬性 (property),也

可具有操作 (behavior),也就是函式。
假如我們要使用一維陣列來模擬二維陣列,那麼就無法使用 ary[x][y] 這種表示法來設定或取得陣列成員。不過我可以定義一個

set 方法來設定成員變數,而以 get方法來取得成員變數值。原型函式定義如下:

function Array2D(x,y){ // 以一維陣列模擬二維陣列的原型物件
this.length = x * y; // 陣列總長
this.x = x; // x 維度長度
this.y = y; // y 維度長度
for(var i = 0; i < this.length; i++) // 初始各元素值為 null this[i] = null; this.get = function(x,y){ // 成員函式:取得陣列第 [x,y]個元素值 return this[x*this.x + y]; } this.set = function(x,y,value){ // 成員函式:設定陣列第 [x,y] 個元素值 this[x*this.x + y] = value; } } 我們接著來使用它: var a2d = new Array2D(10, 10); // 建立新的「二維」陣列 a2d.set(1, 3, "ABC"); // 設定「二維」陣列元素值 a2d.set(2, 6, "XYZ"); a2d.set(9, 9, 1000); alert( a2d.get(1,3) ); // 取得「二維」陣列元素值,並顯示出來 alert( a2d.get(2,6) ); alert( a2d.get(9,9) ); Member Function Outside of Constructor
我們也可以將物件成員函式寫於原型物件之外。以下的Array2D物件與上一個範例中的 Array2物件有相同的作用,只不過這次是寫在原型物件之外。

function Array2D(x,y){ // 以一維陣列模擬二維陣列的原型物件
this.length = x * y; // 陣列總長
this.x = x; // x 維度長度
this.y = y; // y 維度長度
for(var i = 0; i < this.length; i++) // 初始各元素值為 null this[i] = null; this.get = Array2DGet; // 用這種方式把成員函式掛進來 this.set = Array2DSet; } function Array2DGet(x,y){ // 成員函式:取得陣列第 [x,y] 個元素值 return this[x*this.x + y]; } function Array2DSet(x,y,value){ // 成員函式:設定陣列第 [x,y] 個元素值 this[x*this.x + y] = value; } Dynamic Object Function
這裡說明如何為一個已定義物件,動態的加上其他操作的方法。
如 果一物件已定義完成,而您也使用它來建立了新的物件,這時候您想為原型物件增加新的操作 (而不修改原型物件的原始碼),讓

所有該物件的複本都能使用該操作,該如何達成呢?方法是使用物件的 prototype 屬性。以下這個例子,為 Array 這類 Object 在

執行期加入一個 max 方法,以取得陣列元素之最大值 (修改自微軟 jscript.chm之範例):

function array_max(){ // 定義求取 Array 最大值之函式
var i, max = this[0];
for (i = 1; i < this.length; i++){ if (max < this[i]) max = this[i]; } return max; } Array.prototype.max = array_max; // 在 Array 原型中加入 max 函式 上面的程式碼,首先建立一個 array_max 方法,以求取陣列之最大元素。接著將這個方法設定給 Array 原型物件。 var x = new Array(1, 2, 3, 4, 5, 6); // 透過 Array 建構子建立一陣列 // 想求取 x 中某一元素之最大值 var y = x.max( ); // 取得 x 之最大元素 Dynamic Mix in
假如物件 dynamic 有 mathod1, method2 兩個函式;而另一物件 main 有 methodA 及 methodB 兩個函式。現在我想把 dynamic 的

所有特性 (feature) 匯入到 main 中,我們可以在 main 中加上一個 imports 函式:

function main(){ // main 之建構子
// ...
this.imports = function (object) {
if( typeof object =="object")
for( value in object )
this[value] = object[value];
}
// ...
}

obj = new main();

main.imports(new dynamic()); // 匯入 dynamic 物件之所有功能

這個 imports 函式可以動態的為 main 加上另一物件的所有操作。這種 Mix in 的功能可是 C++/Java 的 static type 語言所望塵莫及的。


2008年3月3日 星期一

因為工作需要,搞了些web的東西,做完之後最少測試Firefox跟IE的狀況。
通常來說都是layout出問題的機率比較大,這次居然是javascript出問題,好鳥的IE。

OnChange這個event 沒辦法正確的在IE 6被觸發。所以我只好想了一個workaround。這個workaround是針對checkbox還有我的需求而選出來的,在不同的狀況下,也許要用Onblur()才能達到想要的效果。

以下是測試區,Firefox可以正確無誤的運作,IE只能對Onclick做正常的運作。


onchange:
可以正確的在FireFox上執行, 但IE在change 之後還要再做一個click的動作才會觸動OnChange。
===這邊是OnChange在控制的===

onclick:
運用在checkbox上可以達到我預期的效果且IE跟Firefox都能正常運作。
===這邊是OnClick在控制的===




瀏覽器請選FireFox,以獲得最佳流覽效果。

偏偏很多人愛用微軟出的軟體寫網頁,尤其是金螎業的電子交易系統,只跟IE相容,不知道是金融業的網頁人員太差還是太懶。


2008年1月18日 星期五

mirror to


2007年12月20日 星期四

程式怎麼寫都行,complier看的懂最重要
但是....

如果有一天你寫的程式必需加入到linux kernel (為什麼要機會加入呢? 遇到你就知道了! kernel code)
我在這邊告訴你... 他們對code style是有"龜定"的

在此之外... 很少有單位對code style做嚴格的要求
因此,這唯一的"龜定" 不彷趁早習慣
除非... 抱定一輩子不跟linux kernel打交道的決心 (真這麼有信心? 想想舉手之勞做環保...就這樣想吧!)

好,那就來看看他們有什麼"龜定"吧...!


-------------------以下為原文-------------------
Linux kernel coding style
This is a short document describing the preferred coding style for the linux kernel. Coding style is very personal, and I won't force my views on anybody, but this is what goes for anything that I have to be able to maintain, and I'd prefer it for most other things too. Please at least consider the points made here.

First off, I'd suggest printing out a copy of the GNU coding standards, and not read it. Burn them, it's a great symbolic gesture.

Anyway, here goes:

Chapter 1: Indentation
Tabs are 8 characters, and thus indentations are also 8 characters. There are heretic movements that try to make indentations 4 (or even 2!) characters deep, and that is akin to trying to define the value of PI to be 3.

Rationale: The whole idea behind indentation is to clearly define where a block of control starts and ends. Especially when you've been looking at your screen for 20 straight hours, you'll find it a lot easier to see how the indentation works if you have large indentations.

Now, some people will claim that having 8-character indentations makes the code move too far to the right, and makes it hard to read on a 80-character terminal screen. The answer to that is that if you need more than 3 levels of indentation, you're screwed anyway, and should fix your program.

In short, 8-char indents make things easier to read, and have the added benefit of warning you when you're nesting your functions too deep. Heed that warning.

Chapter 2: Placing Braces
The other issue that always comes up in C styling is the placement of braces. Unlike the indent size, there are few technical reasons to choose one placement strategy over the other, but the preferred way, as shown to us by the prophets Kernighan and Ritchie, is to put the opening brace last on the line, and put the closing brace first, thusly:

if (x is true) {
we do y
}
However, there is one special case, namely functions: they have the opening brace at the beginning of the next line, thus:

int function(int x)
{
body of function
}
Heretic people all over the world have claimed that this inconsistency is ... well ... inconsistent, but all right-thinking people know that (a) K&R are right and (b) K&R are right. Besides, functions are special anyway (you can't nest them in C).

Note that the closing brace is empty on a line of its own, except in the cases where it is followed by a continuation of the same statement, ie a "while" in a do-statement or an "else" in an if-statement, like this:

do {
body of do-loop
} while (condition);
and

if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
Rationale: K&R.

Also, note that this brace-placement also minimizes the number of empty (or almost empty) lines, without any loss of readability. Thus, as the supply of new-lines on your screen is not a renewable resource (think 25-line terminal screens here), you have more empty lines to put comments on.

Chapter 3: Naming
C is a Spartan language, and so should your naming be. Unlike Modula-2 and Pascal programmers, C programmers do not use cute names like ThisVariableIsATemporaryCounter. A C programmer would call that variable "tmp", which is much easier to write, and not the least more difficult to understand.

However, while mixed-case names are frowned upon, descriptive names for global variables are a must. To call a global function "foo" is a shooting offense.

Global variables (to be used only if you really need them) need to have descriptive names, as do global functions. If you have a function that counts the number of active users, you should call that "count_active_users()" or similar, you should not call it "cntusr()".

Encoding the type of a function into the name (so-called Hungarian notation) is brain damaged - the compiler knows the types anyway and can check those, and it only confuses the programmer. No wonder MicroSoft makes buggy programs.

Local variable names should be short, and to the point. If you have some random integer loop counter, it should probably be called "i". Calling it "loop_counter" is non-productive, if there is no chance of it being mis-understood. Similarly, "tmp" can be just about any type of variable that is used to hold a temporary value.

If you are afraid to mix up your local variable names, you have another problem, which is called the function-growth-hormone-imbalance syndrome. See next chapter.

Chapter 4: Functions
Functions should be short and sweet, and do just one thing. They should fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24, as we all know), and do one thing and do that well.

The maximum length of a function is inversely proportional to the complexity and indentation level of that function. So, if you have a conceptually simple function that is just one long (but simple) case-statement, where you have to do lots of small things for a lot of different cases, it's ok to have a longer function.

However, if you have a complex function, and you suspect that a less-than-gifted first-year high-school student might not even understand what the function is all about, you should adhere to the maximum limits all the more closely. Use helper functions with descriptive names (you can ask the compiler to in-line them if you think it's performance-critical, and it will probably do a better job of it that you would have done).

Another measure of the function is the number of local variables. They shouldn't exceed 5-10, or you're doing something wrong. Re-think the function, and split it into smaller pieces. A human brain can generally easily keep track of about 7 different things, anything more and it gets confused. You know you're brilliant, but maybe you'd like to understand what you did 2 weeks from now.

Chapter 5: Commenting
Comments are good, but there is also a danger of over-commenting. Never try to explain how your code works in a comment: it's much better to write the code so that the working is obvious, and it's a waste of time to explain badly written code.

Generally, you want your comments to tell what your code does, not how. Also, try to avoid putting comments inside a function body: if the function is so complex that you need to separately comment parts of it, you should probably go back to chapter 4 for a while. You can make small comments to note or warn about something particularly clever (or ugly), but try to avoid excess. Instead, put the comments at the head of the function, telling people what it does, and possibly why it does it.

Chapter 6: You've made a mess of it
That's ok, we all do. You've probably been told by your long-time unix user helper that "GNU emacs" automatically formats the C sources for you, and you've noticed that yes, it does do that, but the defaults it uses are less than desirable (in fact, they are worse than random typing - a infinite number of monkeys typing into GNU emacs would never make a good program).

So, you can either get rid of GNU emacs, or change it to use saner values. To do the latter, you can stick the following in your .emacs file:

(defun linux-c-mode ()
"C mode with adjusted defaults for use with the Linux kernel."
(interactive)
(c-mode)
(setq c-indent-level 8)
(setq c-brace-imaginary-offset 0)
(setq c-brace-offset -8)
(setq c-argdecl-indent 8)
(setq c-label-offset -8)
(setq c-continued-statement-offset 8)
(setq indent-tabs-mode nil)
(setq tab-width 8))
This will define the M-x linux-c-mode command. When hacking on a module, if you put the string -*- linux-c -*- somewhere on the first two lines, this mode will be automatically invoked. Also, you may want to add

(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
auto-mode-alist))
to your .emacs file if you want to have linux-c-mode switched on automagically when you edit source files under /usr/src/linux.

But even if you fail in getting emacs to do sane formatting, not everything is lost: use "indent".

Now, again, GNU indent has the same brain dead settings that GNU emacs has, which is why you need to give it a few command line options. However, that's not too bad, because even the makers of GNU indent recognize the authority of K&R (the GNU people aren't evil, they are just severely misguided in this matter), so you just give indent the options "-kr -i8" (stands for "K&R, 8 character indents").

"indent" has a lot of options, and especially when it comes to comment re-formatting you may want to take a look at the manual page. But remember: "indent" is not a fix for bad programming.

-------------------原文結束-------------------
原文載於 : http://pantransit.reptiles.org/prog/CodingStyle.html
其實只要安裝kernel source 都可以找到這份文件!

沒有很難吧....!
看他說的彷彿立意良善....
趁早習慣,有益無害....

有在寫 C 就趁早習慣囉....


2007年1月1日 星期一


nothing


總網頁瀏覽量