2010年1月30日 星期六

程式Compile流程

一般寫程式的流程為:編譯-載入-執行。

編譯Compile流程

一個完整的編譯過程通常需要包含以下的4個程序:

1. Preprocess 預處理器。
2. Compiler 編譯器。會處理副檔名.c的檔案,產生副檔名.as的組譯檔。
3. Assembler 組譯器。會處理副檔名.as的組譯檔,產生副檔名.o的中間檔。
4. Linker 連結器。會處理副檔名.o或.obj的中間檔。

預處理器(Preprocess)

預處理器會在進行編譯前先處理原始碼內像#ifdef、#define相對簡單的詞句替換、和一些巨集代換的功能。

編譯器(Compiler)

編譯器是將高階語言所寫的原始程式,翻譯成機器語言組成的目的程式。在編譯過程中,會執行下列的步驟:

* 語彙分析(Lexical analysis)。分析程式中每一個字眼(word):註解(comment, 在編譯過程會被編譯器忽略掉)、關鍵字(keyword, 如int、for、while等)、常數(constant, 如1、12、”embedded”等)、運算子(operator, 如+、-、*、/等)。

* 語法分析(Syntax analysis)。主要是將程式符號,轉換成階層式的語法樹(Syntax tree)符號表示。在這個語法樹中,在正常情況下,階層最高的節點(node)為assign的符號,其餘的節點為其他的運算元符號,而葉子(leaf)就都是變數的標記(token)。

* 語意分析(Semantic Analysis)。是藉由語法樹(Syntax tree)來分析程式的邏輯與語法是否符合規定。這個階段就是用來分析程式的「文法」是否正確,已經從文字符號的階段進入了程式語意的判別。

* 中間碼的產生(Intermediate code generate)。是從語法樹(Syntax tree)中,以一個節點(node)為基本單位,從最底層的節點依序往上,拆解成一個個最基本的運算式,而每一個節點也會賦予一個暫時性的符號。

* 程式碼的最佳化(code optimize)。基本上就是減少一些不必要的暫時性節點符號。當然,另外還有一些特別的最佳化演算法也會在這個階段使用,例如針對迴圈邏輯的最佳化有三種知名的演算法: code motion、induction variable、strength reduction;因為迴圈邏輯在語法上是最沒有執行效率的語法之一,因此需要特別的最佳化。或者,有時候編譯器會調整程式的前後順序,為了在下一階段程式碼的產生過程中,暫存器的使用數目降低。

* 程式碼的產生(code generate)。以c語言為例,這裡就是將最佳化後的中間碼,搭配微處理器的暫存器,逐一轉換成組合語言。

組譯器(Assembler)

組譯器會將組合語言的原始程式,翻譯成機器語言組成的中間檔 ".obj"或".o"。

連結器(Linker)

連結器會將中間檔 obj files 連結起來,找到symbol(函式,變數名)與程式庫(shared obj)中的副程式,產生可執行的obj檔(executable obj)。

小結

「編譯-載入-執行」方式的缺點是產生的 List檔,其定址 Address 為相對位址,也就是說,每個source的各個section (Absolute section除外) 都由位置 "0" 排起,非常不方便作程式 debug用。但是產生 .obj 檔仍然有一個優點,就是會收錄 .lib 檔,以後要重新 make 時,只需要直接指定使用的 library 即可。

因為目前電腦速度已經非常快,對所有檔案做編譯及連結幾乎都是瞬間完成,所產生的 List檔已包含最終的正確位址,用來作為程式的 Debug 非常好用,如果沒有特殊需要的話,已經沒有必要產生中間檔 .obj。

參考資料:
程式Compile流程
Gcc編譯流程解析

2010年1月28日 星期四

extern與static的問題

在extern與static是不能同時形容一個變數。

而在extern基本上,一定是形容全域變數,若不是形容全域變數,就沒有意思了,原因是,他就是說在其它.c檔有宣告某一個變數,可以讓我們使用,倘若在其它的檔案,他不是全域變數,那就沒有辦法存取它,那還是會發生錯誤!

你或許對以下文章有興趣:
static
extern

參考資料:
static函數的用途?
不懂C語言的extern是做什麼的

2010年1月23日 星期六

vim 的 search 搜尋功能

若要在一個文件中,同時找到「肥仔魚」、「肥仔豬」、「肥仔貓」,有一個規則的字串,可以使用正規表示式。
/肥仔[魚豬貓」
就可以找到,[]表示的是一個字元,但是,可以被選擇的就是中間的那三個字元~

如果我們今天要找的是英文文件,想要搜尋的 lemon tree、lemon soup、lemon juice 的話,就必需使用「\|」這個「或(or)」運算
/lemon tree\|lemon soup\|lemon juice

想要搜尋的東西會是像這樣 1234- 1234-5 1234-56 1234-567 1234-789 1234-2399 1234349898。

我們大概可以分析一下,這個字串大約是以1234開頭,然後跟上或不跟上「-」之後,再接上一堆數字。先把指令給大家:

/1234[-]\{,1}[0-9]\{1,}

或是:

/1234-[0-9]\{1,}\|1234[0-9]*

我們可以先看第一個方法,在第一個方法裡面用了兩個特別的東西:\{1,}\{,1}。在前面我們剛剛說中括號後面如果不跟上任何東西就表示中括號裡面的某一字元要出現一次。而現在\{n,m}就是用來表示可以對中括號裡面的字元挑選幾次。(選幾次就會出現幾個字元)

\{1,}表示至少要出現一次(至少選一次),而\{,1}表示最多出現一次(最多選一次,不選的話就代表中括號裡面的字元都不出現)。當然我們也可以寫成\{3,9},這就表示可以在中括號裡面的字元挑選三到九次,也就是會出現三到九個中括號裡面出現的字元。

而在第二個方法裡面,則在中括號後面緊跟著一個「*」,這其實代表\{0,},也就是 0 個到任意個都可以的。而中括號裡面我們用了「0-9」這就表示 0123456789 都可以。同樣對於字母我們也可以用「a-z」表示所有小寫英文字母和「A-Z」用來表示所有的大寫字母。

儘管如此,我們可能還是不滿足。舉例來說,我可不可以只找以「傷寒」開頭的字串或是以「主之。」結尾的字串?

假如我們只想找以「傷寒」開頭的字串,可以這樣輸入搜尋命令:

/^傷寒

^」開頭就表示要找的東西是一行的開頭。

但是有時候為了排版需要,在「傷寒」前面可能會出現一些空白或是 tab ,如果我們只是用上面的指令就不夠。所以配合我們剛剛的中括號帶次數的方式就可以做到:

/^[\t <Space>]*傷寒

<Space>是為了網頁展示可能看不到所以用<Space>來表示空白。而「\t」則是 vim 中用來表示 tab ,所以上面的命令就代表一行的開頭有任意個空白或是 tab 的混合,而其後跟上「傷寒」兩個字。

那結尾呢?還記得我們怎麼把游標移到行尾嗎?就是用「$」這個符號。所以要找以「主之」結尾的字串就可以用:

/主之$

不過你可能還是不滿意,比方說 vim 可不可以幫我找出忘了在句末補上句號的地方?可以!我們先看指令:

/.*[^。]$

或是不要看到整句:

/[^。]$

中括號裡面的字元 X 如果前面出現「 ^ 」就表示除了 X 以外的字元都算是想要比對的字元。所以上面第一個的指令就表示搜尋句末沒有句號的行(這一行至少要有一個字元,因為用了[^。]$,而不是 [^。]*$)。第二個指令比較不一樣是只搜尋句末不是以句點結束的字元。其實看哪個指令對你來說比較「順眼」就用哪個。

有關這些特殊符號還有許多更 powerful 的功能,你可以在 vim 的指令模式下打 :h pattern 看更詳細的資料。或用 :h regular 看有關 regular expression 的詳細說明。

現在,你已經可以用 vim 編輯、刪除,也可以做搜尋了,基本的 vim 操作到這裡已經可以說是差不多了。

[2020.05.29 補充]
確認是否是數字
其中包含負數與小數的情況
^-?\s*?([\d\,]+(\.\d{1,})?|\.\d{1,})\s*$


參考資料:
vim 的 search 搜尋功能
javascript - 带小数位的数字,以允许在正则表达式验证中使用逗号

直接透過vim去取代文件內容

在之前,我要取代文件的內容,都是使用外部指令grep,來完成!

雖然,這樣也可以達成,不過,其實透過vim的內建功能就可以達到這一個功能啦~

Q: 選取特定幾行,執行取代的動作
A: 在之前我就要去算由第n行到第m行要執行取代的動作,那麼我就直接使用以下的動作
: n,ms/{pattern}/{string}/gc
而這裡還有另一個方法:
在你想置換部分的開頭按下大寫「V」然後用移動游標(我們之前講的 vim 移動游標的方法在選取模式下都可以用)到你想要的位置之後按「:」就會跳到輸入指令的狀態,如下圖最下面那行看到的一樣:


或者是如果你很確定要從現在游標所在行之後的所有行都置換,可以下成
:.,$s/vim/VIM/g
冒號一開頭的那一小點「 . 」就代表游標現在所在行,「$」則用來表示最後一行。

可以找到系統的相關說明
:h :s

假如我現在有一筆人名、電話的資料,由於是隨手記的,上面自然就是沒有排序過。那沒排序過對於想要在上面找資料的人就很麻煩。萬一人名記不太清楚,電話號碼也記得七七八八,雖然說有 vim 方便的 search 功能,但總是感覺不足。(當然這只是假設情況,因為實際上可能大家都已經建立某種方便搜尋的資料庫了)

我們先假設人名、電話的對應長成這樣:

趙大明  1235478982
錢小名 1223450012
王孫李 5938123812
周渚衛 1384914191
沈以情 2345934981


那我可不可以讓它變成這樣子?

1235478982   趙大明
1223450012 錢小名
5938123812 王孫李
1384914191 周渚衛
2345934981 沈以情


我可以下這樣的指令完成這個工作:

:%s/\([0-9]\{1,\}\)\([^0-9]\{1,\}\)/\2 \1/g

前面部分\([^0-9]\{1,\}\)\( \)括起來的,表示這是一個的單元,之後就可以依照它出現的順序而使用 \1, \2,… ,來代表它。所以我們可以看到[^0-9]就表示非數字的部分,後面的\{1,\}如果你還記得的話,就是代表出現至少一次。可以用「\+」來代表至少出現一次。你可以用 :h /multi 看到更多這些替代符號。

所以把 pattern用\( \)分開之後,我們就可以用 \1,\2 來把他們交換位置。

最短符合

之前提到的 "\{n,m}" 會盡可能的找最長符合字串。若是要找最短符合字串,要改用 "\{-n,m}" 。

譬如說:

/ab\{-1,3}

會與字串 "abbb" 中的 "ab" 符合。因為要求的是最短符合字串,所以只會比對到1個"b"。如果要強制它能比對到比下限多一些的話,還得要多加點東西。

同樣的規則也可以套用到去掉 "n" 或 "m" 的情形。甚至可以同時不寫 "m" 和 "n" ,只留下 "\{-}" 。這個指令的意思是符合零次以上,愈短愈好…所以一定會比對到符合零次。這些規則可以組合使用,譬如:

/a.\{-}b

會對 "axbxb" 中的 "axb" 符合。如果改用:

/a.*b

就會試著找最長符合字串,所以就會符合到整個 "axbxb" 。

[2010.02.27 補充]
把完整的目錄名稱,只留下檔案名稱
例如內容為
d:\work\project\main.c
d:\work\project\make.dxc
d:\work\main.h
可以使用
:%s/.*\\\(\w\+\.\w\+$\)/\1/g
尋找字串,必需滿足以下二個條件
1. 先說明\w\+\.\w\+$的部分,是以尋找符號.前,至少有一個非特殊字元且後面也是至少有一個特殊字元的字串,並且後面就是字尾啦,這樣會找到main.c、make.dxc與main.h;
而用\(...\)把它包起來,就是要把它當作pattern,等一下取代則可以使用。
2. .*\\則表示找到在\前面有任意字元的字串
當內容中,有符合以上的字串,就處理\1這一個動作,也就是把符合這一個字串的部分,整個替換成第一個pattern

現在又想到一個問題,Makefile是沒有副檔名的,所以沒有辦法使用「任意字串.任意字串」當作條件去尋找啦。
還好又想到正規表示式是貪婪的,如何在同一行符合的字串長度有兩個,則他會選則最長的那一個。例如:
d:\work\project\main.c
符合.*\\條件有d:\與d:\work\與d:\work\project\
則,它會選擇最長的部分也就是d:\work\project\
因此,在這裡使用
:%s/.*\\\(.*\)/file name is \1 end/g
就可以取出檔名,並且在前面加入一些字串和後面加一些字串

[Add-20100307-start]
全域性的指令
:[range]g/pattern/[cmd]
cmd 是 ed 可用的指令,預設是 p(print),您可查一下 man ed,就可以知道有什麼指令可用。
需注意的是,d 是行刪除指令,凡含 pattern 的整行都會被刪掉,而且 range 不指定的話,預設是全篇文章,因為 g 就是代表 globe。

Q: 刪除空白行
:g/^$/d
有些書中寫成:%s/^$//g可以刪除空白行,這是錯誤的,因為 :s 這個指令只更動一行裡的內容物,但不會做刪除一行的動作。
[End-20100307-start]

[2010.04.05 補充]
Q: Delete all lines containing which didn’t contain string
A: :v/string/d

Q: want to match all non-printable characters and delete them
A: /\p\@!.
上列後面那一個小數點的意思是說滿足這一個條件的是有幾個字元,因為,上述只有一個小數點,所以是一個字元

Q: 找到不滿足的字串(不含有"String")
A: /\(String\)\@!

Q: 重覆a這一個字元3次
A: /a\{3}

Q: 重覆abc這一個字串元5次
A: \(abc\){5}

[2010.09.22 補充]
Q: 移除每一行最後面多餘的空白
A: %s/ \+$//gc

[2012.02.20 補充]
Q: 尋找最短符合字串,如何把以下內容前面縮寫的部分移到最後,並且加括號
API Application Program Interface
BLDK Boot Loader Development Kit

A: %s/\(^[A-Z]\{-}\) \(.*$\)/\2 \(\1\)/gc

參考資料:
vim 的取代置換功能「s」
vim 的 search 搜尋功能
規則表示式的運用
100 Vim commands every programmer should know
help pattern-multi-items

2010年1月20日 星期三

如何移動無法用滑鼠點不到的視窗

昨天,同事遇到一個問題。

當他在家的時候,他用雙螢幕,而把編譯器的視窗放在延伸的桌面上,也就是第二個視窗裡面。

當他回到公司時,他只有一個螢幕,開啟編譯器時,會跳到延伸的桌面,而他此時又沒有第二個桌面,所以,也沒有辦法用滑鼠把視窗叫到目前的主要畫面!

這個時候,就要用到鍵盤啦~

=========教學開始==============

請先參考下圖,這個視窗基本上根本無法透過滑鼠來移動,唯一可以按的地方只有「關閉」


在所有 Windows 視窗的左上角如果按下滑鼠左鍵會出現一個特殊的選單 (所有版本的 Windows 都有)


而透過「鍵盤」開啟這個選單的方式是 Alt + Space (空白鍵),接著透過鍵盤選取「移動」並按下 Enter


接著按鍵盤的 上(↑)、下(↓)、左(←)、右(→) 就可以移動視窗,只要移動到你覺得差不多可以用「滑鼠」控制的時候,這時再按下 Enter 即可確定視窗位置,該視窗就可以正常移動了!


=========教學結束==============

參考資料:
如何拯救無法移動的 Windows 視窗 (用鍵盤移動視窗的密技)

2010年1月19日 星期二

每一次開機都檢查硬碟的解決方法

公司的電腦,在之前的電腦隨時會當機的情況下,換了一個新的電腦~

誰知道換了新電腦之後,每一次開機都會檢查硬碟~想說是因為硬碟的關係~
還用了檢查硬碟的程式去檢查,結果都是健康!

上網查了一下,喔,才知道是註冊表有出現問題!

解決開機檢查硬碟的方法:
1. 執行 Regedit.exe
2. 找到機碼 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager
3. 該機碼右邊應該有字串 BootExecute 它的值應該不是空白,而是autochk autochk*一類,將值清空!
完成,下次開機應該不會再檢查磁碟。而且不用擔心,真的硬碟出問題還是會檢查的,這個值只是暫存值,照理說磁碟檢查完就會清掉了。而因為某些軟體造成不正確關機時,系統會自動加入值引發下次開機的檢查。

參考資料:
Windows每次開機都檢查硬碟(chkdsk)的解決方法

2010年1月16日 星期六

資料夾分頁工具 - QT Tab Bar

最近在看程式碼時,會開很多資料夾~

常常會在這麼多資料夾中切換來又切換過去~

有一個好用的軟體,叫做QT Tab Bar,可以在一個資料夾視窗中可以有多個資料夾的分頁~

有圖有真像~


安裝完後,除了要重新開機之外,必需要在資料夾視窗工具列空白的地方按右鍵,把QTTabBar叫出來,才會顯示哩~

今天差一點又放棄QT Tab Bar了,原因是,我安裝完之後,到IE工具列的地方按右鍵,看能不能把QTTabBar叫出來,結果,可以,接著,我就想要把它關掉,會出現以下畫面~

結果,我按確定之後停用之後,我哩~在檔案視窗中,就不能使用QTTabBar了~

一定要在IE下,有使用QTTabBar之後,檔案視窗才可以使用QTTabBar~

不過,最後,讓我找到方法了~
在IE的部分先停用了之後,再到IE的工具列的「工具」→「管理附加元件」找到QTTabBar把它啟用就好~
然後,再到檔案視窗中,把QTTabBar叫出來~

[2010.03.12 補充]
有時候,在視窗點檔案的時候,不小心點到旁邊的空白的地方,預設會跳到上一層。
這個時候很討厭,又不能回到剛剛那一個位置。
這個時候就可以把這一個功能關掉啊~
方法如下:
在QT Tab Bar空白的地方按右鍵,

選擇
OptionsWindowUp one level when db1 chicked on folder margin
的選項關掉

參考資料:
QTTabBar & QTAddressBar - 兩款強化檔案總管的工具
完全改造檔案總管的免費工具列:QT TabBar 1.0.16.1
QTTabBar

好用的編輯軟體 - PSPad

雖然,我的目標是使用vim來編輯我的所有程式,但是,當其它人來到我的電腦前面的時候,都會說,你還有其它的編輯器嗎?

在trace code時,source Insight實在好用!不過,缺點就是它不能讀取Unicode的檔案。

另一個選擇就是PSPad,雖然,它沒有像source Insight可以trace,不過,他有一些收尋功能真的不錯用~

像是對每一個資料夾下去收尋、對目前開啟的檔案收尋、目前的檔案收尋~
當然這一些功能在VIM都可以做到,但是,要另外的額外的設定,而且不簡單,現在就急就用章,就先用PSPad來處理吧~

另外PSPad可以讀取Unicode,而vim也可以,不過需要另外設定,請參考解決在vim下可以讀取Unicode的檔案

是免費的,而且,也有免安裝檔哩~

參考資料:
PSPad
PSPad 4.5.4.2356 免安裝中文版

剪貼簿軟體 - ClipX

在寫程式的時候,有時候需要copy多個字串,因為,windows只能copy一個字串,而透過這一個軟體,可以同時複製多個字串,而同時貼上多個字串~同時也包含圖片喔~

以下是軟體圖示,重點是免安裝的喔~~


參考資料:
ClipX
免費剪貼簿增強軟體
ClipX 1.0.3.9c Beta 免安裝中文版

2010年1月6日 星期三

適合程式設計的字型

在寫程式的時候,常常l1i傻傻分不清楚!
O0o也是傻傻分不清楚~
而以下的程式對這一些字元加強~可以讓程式設計師可以清楚的辨識這一些字元~

我試過ConsolasTerminus的字型,都不錯~

目前是使用Consolas字型~

測試一下Consolas字型:
l1i
O0o

測試一下Terminus字型:
l1i
O0o

這一個字型似乎有一點瘦~還是胖胖的一點比較好~

參考資料:
適合程式設計的字型
Terminus font
寫程式用的字型
程式設計師該用的字型
程式設計工程師寫程式專用字型

移除PDF的保護

最近常在看一些spec,而透過PDFXCview(portable)的軟體可以在PDF上加一些註解,不需要透過紙印出來,是一個非常好用的軟體!

不過,常常會遇到PDF被鎖起來了,就沒有辦法在上面加任何東西,這個時候就要尋找可以移除掉PDF密碼的軟體。

以下提供兩個方法:

有公司提供免費的序號,重點是正版的喔~
軟體下載(點選Download)
活動網頁

線上移除PDF保護:
FreeMyPDF
如此就不需要安裝軟體啦~

參考資料:
免費獲得 PDF Password Remover 軟體序號!
FreeMyPDF: PDF文件密碼破解工具(線上版)

2010年1月3日 星期日

"NUMA" 與 "NUMA node"

NUMA全名是Non-Uniform Memory Access 或 Non-Uniform Memory Architecture
由於處理器運算時需要使用記憶體,而處理器運算的速度又大於記憶體,因此整體速度會受到記憶體的限制。所以,如果處理器減少對記憶體存取的次數,可提供更快的執行效率。硬體製造商提供更快速的 L3 快取記憶體( Cache Memory ),可降低存取一般記憶體的次數,但這只是有限的解決方案。

另一方面,增加處理器的數目也是提升整體速度的方法。但在多處理器的情況下,會在記憶體這方面產生前一段所提及的問題,反而拖累整體速度。因為記憶體在同一時間只能讓一個處理器對它做存取動作,這意謂著其它處理器將處於等待的狀態,虛耗時間。 NUMA 架構對這個問題提供了可擴充的解決方案。利用 NUMA ,可以分割記憶體區塊,讓不同處理器可分別使用不同區塊的記憶體。這樣可以避免多處理器同時企圖存取同一區塊記憶體的問題,並改善這方面的速度。

然而,並非所有資料都使用在單一的運算任務(task)裡。多個處理器分工做同一件事,在運算執行過程及運算結束時,仍有可能對同一份資料做存取的動作。為解決這個問題,NUMA 可利用額外新增的軟硬體,將資料在不同的儲存處所之間來回搬動,並維持資料的一致性。不過這也會減慢一些速度。所以在利用 NUMA 提升整體速度這方面,也會受到運算任務的特徵 所影響。

NUMA node
由於處理器運算時脈不斷增快,因此在使用單一系統匯流排的情況下,要支援多處理器所需要的頻寬及其它潛在的需求變的更困難也更昂貴。於是在單一系統匯流排裡使用理想的處理器數目,可避免過多 CPU 產生效率上的浪費。大多數微軟視窗作業系統,在單一系統匯流排上支援四個處理器。

而這樣一個工作小組:一個系統匯流排、幾個處理器、一些記憶體,或一些I/O 次系統,可稱之為 node。硬體發展的趨勢是,高端伺服器可使用不只一個系統匯流排。如此一來,八個處理器就可分為二個 node 。

在這樣的架構下,在 Node 1 裡的CPU 若要存取 Node 2 裡的記憶體的資料,速度將會慢於存取同一個 node 裡的記憶體資料。由硬體製造廠商所組裝的超級電腦,常會提供專屬的連結界面來加大連結的頻寬,並降低存取遠端記憶體所產生的損耗,於是又產生了所謂的 ccNUMA 架構 - Cache coherent NUMA。