在最近碰到的很多bug都是和global變數有關的:
1. 使用curl + openssl做https連線,由於openssl一些變數是用global的,所以在multi-thread會有random crash的情形產生。解決方法是要實作openssl裡面提供的lock callback function。
2. 使用pygtk時,檔名取成gtk.py,造成import module的時候gtk.glade無法讀取。
3. 使用localtime和mktime return回來的 struct tm *,連續的呼叫造成結果都會和最後一次相同。
這些bug都非常的讓人頭痛,因為一開始一定會先查看自己的code是否有問題,或是哪些library沒有裝好之類的。最後在慢慢往下trace時,才會發現到是這樣的問題。
所以說使用global變數是非常容易出錯的做法。更正確的來說,如果你的程式要被別人呼叫,或是要和別人的程式溝通,最好避免使用global變數,以免造成自己和別人的困擾。
而在自製function、class時,如果要取太通用的名字,ex : time、string、...,最好加上一個前置的字串。在某一篇文章裡面他說可以加上你的英文縮寫在前面,以防止別人用跟你一樣的function name或 class name造成錯亂。
參考資料 :
debug 心得
2008年9月19日 星期五
| [+/-] |
少使用global變數的原因 |
2008年9月16日 星期二
| [+/-] |
[ACM] 解題注意事項 |
解了一題簡單的3n+1 problem來玩玩,發現要讓他Accept除了程式正確以外還有很多小地方要注意的。
1. 輸入輸出格式:
輸入通常是利用stdin當輸入,然後會把檔案導到stdin當作測試檔。輸出也是輸出在stdout
2. 對於有時間限制的程式,使用scanf, printf,會比cin, cout好。尤其是大量輸入輸出的程式。
3. long long的輸入輸出format不支援%lld,而是支援%l64d (沒有試過不確定)。
4. 錯誤訊息的順序:
1. Runtime Error, Time Limit Exceed, Memory Limit Exceed or Output Limit Exceed
2. Presentation Error, Wrong Answer
5. 注意輸入輸出的說明,因為測試檔不會公開所以要比較細心,不可只依賴範例檔。
像是在3n+1 problem裡面,範例檔的數字都是由小大到,例如:10 100 或是 100 200。但是最後發現一直無法Accept的原因是他的輸入有可能不照大小,而我由於沒有判斷,所以只會輸出0,就產生了Wrong Answer。
所以除了程式正確以外,小地方也要注意才能看到令人感動得Accept。
參考資料 :
http://acm.pku.edu.cn/JudgeOnline/faq.htm
2008年9月6日 星期六
| [+/-] |
[Vim] 利用ctags找尋函數的tags設定 |
在vim裡面用來找函數定義的時候, 要用ctags產生的對應檔tags來找到位址.
而.vimrc裡面也可以對tags檔的放置位址做設定
像是可以先對所有的C/C++ 系統的.h .c .cpp檔做成一個ctags叫做cpp.tags, 然後在設定時用
set tags=path/cpp.tags來設定要把cpp.tags檔加入搜尋函數定義裡面.
這裡要注意的是, 設定tags和./tags意義是不同的.
tags代表目前vim所在的路徑
./tags代表目前檔案所在路徑
兩者意義是不同的.
因為在vim中開啟檔案可以不用切換到檔案的路徑下, 所以如果要對一個Project做所有的tags搜尋的話, 使用tags是比較正確的, 而./tags只能對某個檔案的目錄做搜尋.
所以一般設定的方式為先找檔案路徑, 再找目前vim的路徑.
而設定如下:
set tags=./tags,tags
參考資料 :
vim裡面的:help tags指令
2008年9月1日 星期一
| [+/-] |
[C++] string::npos |
string::npos的值為 -1,但是因為它的type是size_t也就是unsigned long,所以其實string::npos代表的值為size_t裡面的最大值。
參考資料 :
http://www.cplusplus.com/reference/string/string/npos.html
| [+/-] |
[PyGtk] 把程式縮小到系統工具列(system tray) |
在ubuntu上面用的hinedo這個廣播程式就是用這樣的方式存在於系統工具列裡面,感覺起來方便簡潔,不會佔用到awn的空間。
而利用PyGtk配合上 GnomePythonExtras 裡面的egg.trayicon就能達到這樣的效果。
另外GnomePythonDesktop 也提供了gnome桌面library的interface,對於寫gnome桌面程式有很大的幫助。 (ex:gnome applet)
下面是egg.trayicon的簡單例子(gnome-python-extras-2.9.4/examples/egg/trayicon.py):
#! /usr/bin/python
import pygtk
pygtk.require("2.0")
import gtk
import egg.trayicon
t = egg.trayicon.TrayIcon("MyFirstTrayIcon")
t.add(gtk.Label("Hello"))
t.show_all()
gtk.main()
參考資料 :
http://www.pygtk.org/news.html
| [+/-] |
[MFC] CTime的使用 |
如果要找出一個月的第3個幾個星期3要怎麼做呢?
很簡單的方法就是用CTime從這個月的1號開始,對每一天判斷使否為星期三,再利用CTimeSpan設定一天的長度往後加。如此在數到第三個星期三時,就知道是哪一天了。這是一個雖然暴力但是很簡單的做法。
程式碼:
//下面這段程式碼會找出這個月的第三個禮拜三
CTime Find3rdWed()
{
//取得今天的時間
CTime now = CTime::GetCurrentTime();
//從這個月的1號開始 (year, month, day, hour, min, sec)
CTime wholeMonth(now.GetYear(), now.GetMonth(), 1, 0, 0, 0);
//設定一天的長度
CTimeSpan aDay(1, 0, 0, 0);
//禮拜三count
int wedCount = 0;
//尋找第三個禮拜三, 只檢查28天, 因為第三個禮拜三一定在28日以前, 並且配合最短日期的月份
for(int i = 1;i <= 28;i++)
{
//sunday = 1, monday = 2, ...
if(wholeMonth.GetDayOfWeek() == (1 + 3))
wedCount++;
if(wedCount == 3)
{
//find !!
return wholeMonth;
}
//檢查下一天
wholeMonth = wholeMonth + aDay;
}
}
參考資料 :
http://blog.yam.com/swwuyam/article/12603979
2008年8月19日 星期二
| [+/-] |
[Blogger] 貼code語法變色 |
之前語法變色使用了 google code prettify,用起來蠻簡單的,但是還是有一些缺點:
1. 在貼code的時候對於特殊符號 "<" ">" 需要做encode不然會造成貼出來的內容亂掉,當然這不是它的錯誤,而是blogspot會將html語法做一些處理,所以會去掉一些內容。
2. 雖然有python的語法變色,但是在經過重新編輯之後,有些空白會被吃掉,造成要把貼上的code複製來執行時要重新排版。
因此我決定用另外一種語法變色的方法:直接產生html語法。
因此貼上code的流程變成:
1. 編輯好程式碼
2. 複製程式碼到http://tohtml.com/這個網站,產生相對應的html碼
3. 複製html碼到blogspot
這樣做其實用prettify也是可能達到一樣的效果,但是就不必用
code來包住code部分,只是中間需要經過轉換比較麻煩而已。
缺點則是有些中文會怪怪的?
重點是它的顏色我覺得比較好看...^^,目前先暫時試試看,等以後有更好的解決方法在說。
測試:
# -*- coding: cp950 -*-
from xml.dom.minidom import parseString
#import xml.dom.minidom
xmlDoc = open("D:\\2.txt").read() # 讀取檔案到string xmlDoc
xmlDoc = unicode(xmlDoc, "big5").encode("utf8") # 把xmlDoc(big5編碼)變unicode, 在變成utf8 text code
doc = parseString(xmlDoc)
query = "名稱"
query = unicode(query, "big5") # 把query變成unicode, 以供xml parser查詢節點, 因為xml parser內部以unicode形式運作
eles = doc.getElementsByTagName(query) # 查詢tag name為query的節點
for ele in eles: # 印出節點text value
print ele.firstChild.data.encode("big5") # 把unicode編碼成big5輸出
參考資料 :
http://tohtml.com/
2008年8月15日 星期五
| [+/-] |
[Vim] Folder, 視窗切換, 尋找關鍵字 |
Folder:
zr (reduce):open all folder
zm (more):close all folder
zo (open):open folder
zc (close):close folder
r, m, o, c 如果用大寫取代,則是代表會用recursive的方式將folder下的folder也執行這個動作。
視窗切換:
ctrl w + 上下左右:代表切換到相對應的上下左右的視窗
尋找:
/keyword:向下尋找keyword
?keyword:向上尋找keyword
n:正向尋找下一個 (原本向下就繼續向下找,向上就向上找)
N:反向尋找下一個
qa:關閉所有window
參考資料 :
大家來學 Vim 一個歷久彌新的編輯器
| [+/-] |
[Python] 字串的編碼 |
在Python裡面的處理主要是以UTF-8的方式來處理字串,所以在抓一些繁體中文的文字檔時,要先把他轉成UTF-8的形式。
轉換的方式為:
try:
utf8_string = unicode(cp950_string, "cp950").encode("utf8")
except:
print "can't transfer"
做法大致上是先把字串用unicode這個function decode成unicode的形式,再用encode這個function轉成你想要轉的編碼。
這裡的例子是將繁體中文轉成utf8,而編碼使用cp950是因為它支援一些big5沒有支援的繁體中文字。
如果沒辦法將編碼轉成unicode的情況,會產生expection,如果不catch的話程式會中止。在這裡很簡單的印出錯誤訊息。
參考資料 :
http://hoamon.blogspot.com/2008/05/python-big5.html
2008年8月13日 星期三
| [+/-] |
[Unix] setenv Memory Leak的問題 |
最近為了程式自己會莫名其妙的長大而苦惱,但是去看code卻也沒有發現什麼忘記delete或是free的pointer。本來為了避免這些麻煩,所以大部分的資料都是用string或是stl的container來實作,沒想到還是遇到這樣的問題。
把code翻了又翻,最後幾乎把所有可能發生的function call 都加上memory leak去google搜尋,結果發現了下面的man page,告訴我們說如果setenv被連續使用時,set的value長度不一樣,他會自己重新malloc一個新的記憶體,舊的記憶體就會造成memory leak了。
居然和系統(OpenBSD)上面的man page寫的不一樣,如果沒有用google search的話,我大概還在找到死吧。只能說不經一bug,不長一智...QQ。
參考資料 :
http://www.manpagez.com/man/3/setenv/
2008年8月1日 星期五
| [+/-] |
[C++] class member function使用template注意事項 |
在寫一個class的時候,大多習慣把prototype放在.h檔,而定義則放在.cpp檔。
但是當你的member function有使用template時,如果把定義還是放在.cpp檔中,
在link的時候會出現unresolved external symbol,也就是找不到這個function。
所以必須要把這些有用template的function也放在.h檔裡面定義,這樣template就可以正確產生
不同type的function instances。
參考資料 :
http://bytes.com/forum/thread165359.html
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.7
2008年7月25日 星期五
| [+/-] |
[vim] 自訂專案開啟 (project.vim taglist.vim) |
在程式寫很大的時候,常常要編輯很多檔案。雖然名字取的好可以幫助記憶,但是還是需要輸入很多指令來切換編輯檔案。
下面的方式就是用一些vim的plugin,來達到輕鬆的專案開啟以及管理。也能夠很容易的做trace code的動作。
要達要目標我們需要2個vim plugins
1. taglist
2. project
taglist
source code browser,用來方便瀏覽各種語言的原始碼。配合ctags所產生的tags,能跳到variable和function的所在位址。
設定:
1. 確認ctags為Exuberant ctags 5.0以上,vim版本要6.0以上。
2. 安裝taglist.vim這個plugin
3. 在.vimrc設定
nnoremap
nnoremap
project.vim
產生一個project的檔案瀏覽器。
設定:
1. 安裝project.vim
2. 在.vimrc設定
" Open default Project (in ~/.vimprojects)
nnoremap
" taglist 執行的ctags的路徑, 在這裡安裝在家目錄底下
let Tlist_Ctags_Cmd='~/bin/ctags'
" 自動更新tags
function UPDATE_TAGS()
call system("ctags -R")
endfunction
autocmd BufWrite,BufWritePost *.cpp,*.h,*.c :call UPDATE_TAGS()
3. 設定.profile (.cshrc)
for .profile
alias openproj='ctags -R;vim +Project'
for .cshrc
alias openproj 'ctags -R;vim +Project'
使用方法:
在專案的目錄下(source code存放的目錄),輸入
$openproj
開啟檔案,第一次要在project的視窗裡面做設定。
在project視窗輸入'\C'
根據出現的提示做設定
Enter the Name of the Entry: MyProject #專案名稱
Enter the Absolute Directory to Load:/home/powentan/project #專案絕對路徑
Enter the CD parameter:#輸入enter
Enter the File Filter: *.cpp *.h #要加入專案的檔案格式
設定好了以後會產生叫做~/.vimprojects存放你的專案設定,之後再用openproj開啟檔案時,就會自動load專案設定檔。
開好專案以後,選取空白的視窗,按下
產生好了以後按
利用project browser (project.vim)跟source code browser (taglist.vim),我們就能很方便的進行code的修改和trace。
參考資料 :
Using vim as an IDE all in one
vim: lightning fast navigation in a large software project
2008年7月24日 星期四
| [+/-] |
[google] google bookmark的使用 |
目前使用的網路書籤為google bookmark,配合上firefox的GMarks這個plugin,在瀏覽和管理上都相當的方便。GMark可以在側欄開啟,比起在menubar上面好用很多。在IE 6.0上面使用menubar來瀏覽書籤移動會變的卡卡的不好用,用側欄開啟就沒有這個困擾。
另外google bookmark還能在google notebook裡面瀏覽和編輯,增加了很多方便性。
還有匯出的功能,這樣就算不用google bookmark也不怕因為書籤被綁死還無法使用其他服務,在這點google的"Don't be evil"還算蠻好的。
在使用書籤要注意的一點是,如果一個書籤有好幾個tags,而只要刪除其中的一些tags,要使用移除分類標籤這個功能,而不是使用刪除。如果用刪除的話,整個書籤就會完全被刪除,唯一補救的方法就是在google notebook裡面的垃圾桶救回。
2008年7月15日 星期二
| [+/-] |
[Unix] 轉換不同時區的時間 |
轉換不同地方的時間因為有些地區的夏季時間(day light saving time)不同,所以不能只用和GMT
的差距來計算,還要知道夏季時間差、開始以及結束,非常不方便。
因此使用環境變數"TZ"來設定系統的時間,只要知道那個地區的time zone string就能方便的進行轉換。
time zone string在系統的位址為 /usr/share/zoneinfo 底下的檔案和資料夾就是代表各地區的time zone string。
例如:台北的為Asia/Taipei,是在Asia資料夾底下的Taipei檔案,而英國倫敦則是Europe/London。
在shell底下只要用下面的指令就可以把目前系統時間轉換成當地時間:
for ksh:
$TZ="Europe/London";export TZ
for csh:
$setenv TZ "Europe/London"
而在C程式裡面則是呼叫setenv這個function:
setenv("TZ", "Europe/London", 1);
在不同地方時間的轉換則是用下面的方法:
1. 取得source地區的系統時間
2. 轉換到destination的時區
3. 利用source地區的系統時間,經由localtime轉變成destination的struct tm時間。
參考資料 :
| [+/-] |
[Socket] 用Multicast來傳輸資料 |
unicast, multicast, broadcast 介紹三種的網路傳輸方式。
其中 Multicast 是用廣播的方式,將資料傳送給所有加入群組的 ip。
IP區段為:224.0.0.0 ~ 239.255.255.255
下面介紹如何設定傳送和接收 Multicast的 Socket。
標頭檔:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <err.h>
#define PORT 6000
#define GROUP_IP "224.0.0.1"
1. 首先產生一個socket,設定為datagram
sock = socket(AF_INET, SOCK_DGRAM, 0);
2. 設定sockaddr
struct sockaddr_in addr;
bzero(&addr, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(GROUP_IP); //傳送要設定傳送的multicast ip
//接收則是要將ip設定成INADDR_ANY
//透過bind來接收multicast資料
addr.sin_port = htons(PORT);
3. 接收設定資料要進行bind和設定multicast addr
addr.sin_addr.s_addr = inet_addr(INADDR_ANY);
//bind
if (bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0)
{
perror("bind");
exit(1);
}
mreq.imr_multiaddr.s_addr = inet_addr(GROUP_IP);
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(struct ip_mreq)) < 0)
{
perror("setsockopt mreq:");
printf("%d %s\n", errno, strerror(errno));
exit(1);
}
4. 傳送和接收
傳送:
sendto(sock, buf, bufLen, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr));
接收:
u_int addrLen = sizeof(struct sockaddr);
recvfrom(sock, buf, bufLen, 0, (struct sockaddr *)&addr, &addrLen);
參考資料 :
unicast, multicast, broadcast - http://www.hoyo.idv.tw/hoyoweb/document/view.php?sid=109&author=hoyo&status=view
2008年7月8日 星期二
| [+/-] |
[Vim] Class Browser : Taglist |
taglist是一個vim的class browser plugin,它能讓vim編寫程式更方便。
設定方式:
1. exuberant ctags 版本要在5.0以上
2. 下載taglist
3. 如果沒有建立過vim的plugin,要建立~/.vim,以及~/.vim/plugin這兩個目錄
4. 把taglist解壓縮,把裡面的 plugin/taglist.vim複製到 ~/.vim/plugin底下
5. 在.vimrc裡面加入 nnoremap <silent> <F8>
以上設定完畢,只要在進入vim時按F8,就能把這個檔案的class browse顯示在視窗左邊。
如果要一次開啟整個資料夾,也可以用以下的方法:
:TlistAddFilesRecursive /my/project/dir *.c
這樣就能一次把/my/project/dir 底下的所有.c檔匯入。
TlistAddFilesRecursive是把目錄底下的所有檔案以遞回方式全部載入,而TlistAddFiles則只載入這個目錄底下的檔案。
參考資料 :
Taglists plugin for Vim - http://bubudog.blogspot.com/2007/01/taglists-plugin-for-vim.html
2008年7月1日 星期二
| [+/-] |
wxPython : 能改變顏色的文字編輯區塊StyledTextCtrl |
我們在編輯程式的編輯器中,顯示程式碼的區塊能根據不同語言的程式關鍵字而變色。
這樣的編輯區塊在wxPython裡面也有。
wx.stc.StyledTextCtrl:由Scintilla這個open source的編輯套件移植過來的,可以設定一些和編輯器相關的設定。
stc = wx.stc
stc.SetText(text) #設定string text到editor中
stc.SetKeyWords(keywordset, keywords) #設定editor的keyword
stc.SetCurrentPos(pos) #設定目前的位址
用這個元件我們就可以實作出屬於自己的editor。
參考資料 :
StyledTextCtrl - http://www.wxpython.org/docs/api/wx.stc.StyledTextCtrl-class.html
2008年6月27日 星期五
| [+/-] |
gdb的一些常用指令 |
backtrace(bt):顯示程式目前的stack狀態,用於檢查dump core很方便。
frame #:配合backtrace的結果,選擇要跳到的stack #,就可以檢查某個stack的狀態。
在多個source files裡面跳到其他file:list filename:1,用來跳到filename這個檔案的第一行。
用 list 也可以跳到某個檔案的某個function,list filename:function。
參考資料 :
http://www.study-area.org/cyril/opentools/opentools/x1253.html