25 5月 2013

[C/C++] 研究long long * float overflow 可能導致的誤差

最近看bug看到一個奇怪的現象,在64bit的AP執行時,long long * float會有誤差出現,但是32bit的AP卻沒有這樣子的問題出現,直覺上不是應該32bit的AP比較會有問題嗎!?

先來看一下 long long 跟 float ,long long的size是8個byte,float的size是4個byte
long long * float,compiler會將結果存到float的temp變數裡,此時誤差就可能會出現了,但是這個誤差是「有條件」地出現,並不是任何long long的數字乘上float都會產生誤差的

以一個簡單的程式來驗證是否會產生誤差
bool check_longlong(long long v1)
{
    float f = 1.0f;
    long long v2 = long long( v1 * f );
    printf("ori value=%lld, new value=%lld, ori==new=%d", v1, v2, v1==v2);
    return v1==v2;
}

int _tmain(int argc, _TCHAR* argv[])
{
    check_longlong(0xF0000000000);//true - OK
    check_longlong(0x0FFFFFFFFFF);//false - Error!
    check_longlong(0x0FFFFFF);//true - OK
    check_longlong(0x1FFFFFF);//false - Error!
    return 0;
}


24 5月 2013

[C/C++] 使用STL時,混用Debug & Release Mode的DLL or LIB可能會造成 Crash!

當你的Release mode的EXE,使用Debug mode的DLL,中間如果有操作(new/delete)STL的container,很容易讓AP crash,包括下列的error ...
  • Debug Assertion Failed
  • _BLOCK_TYPE_IS_VALID
  • _CrtIsValidHeapPointer

[Python] 為Python2.5 unittest 加上setUpClass & tearDownClass 的功能

最近使用 Sikuli 替Project作AutoTest的功能,以Python的unittest為架構下去撰寫,發現有些綁手綁腳的地方,因為Sikuli是使用Jython 2.5,連帶的unittest也止於Python 2.5的版本。由於測試的項目眾多,需要撰寫多個TestCase,所以setUpClasstearDownClass更顯得重要,可以為每個TestCase做pre-process與post-process。偏偏setUpClass與tearDownClass是在Python 2.7後才支援的,所以想在Sikuli裡套用的話,必須自己加一些Code才行了。

23 5月 2013

[C/C++] 取得LIB目前的DLL module path

如果寫了一個LIB or Cpp檔,讓多個DLL module include使用,該如果拿到目前DLL的module path?

GetModuleFileName() 參數hModule傳NULL的話,只能知道執行檔exe的路徑
要想知道自己在哪個DLL module的話,必須埋一些code才行

EXTERN_C IMAGE_DOS_HEADER __ImageBase
//...
WCHAR dll_path[MAX_PATH] = {0};
GetModuleFileNameW((HINSTANCE)&__ImageBase, dll_path, _MAX_PATH);

Reference :

22 3月 2013

[C/C++] General pointer type for support x86 & x64

一個pointer的size在x86跟x64的環境裡是不一樣大的

  • x86's pointer size = 4 bytes
  • x64's pointer size = 8 bytes
如果你在程式中用int or long去儲存一個pointer的話,可能在compile成x86可以work,但是compile成x64執行的話,可能就會exception了

所以建議是用標準的 uintptr_t / intptr_t 去儲存pointer,uintptr_t在copmpile成x86時的size是4 bytes,x64是8 bytes,它在C++11時才被列入標準,但在大部分的C++03的compiler已經支援了

include header : <cstdint>

Reference : 

10 3月 2013

[wxWidgets] function 傳入wxString的不定參數

在C/C++裡有不定參數的功能,讓一個function可以傳入不固定數目的參數,在function裡,透過va_list, va_arg() 把參數一個個抓出來。

在wxWidgets裡,擁有特有的字串類別wxString,用法跟std::string, std::wstring稍稍不同(多了很多API)。

std::string/std::wstring可以透過c_str()取得的內部字串buffer (char*/wchar_t*)
wxString也可以透過c_str()取得內部字串的buffer,型別是wxChar

wxChar是wxWidgets定義的,會根據compile定義的wxUSE_UNICODE(是否為unicode的build)分別對應到unicode : wchar_t, ansi : char

由於wxString是wxWidgets包裝起來的class,若將它傳進function當不定參數之一,va_arg()將無法取得wxString正確的字串內容,所以如果要將wxString的字串傳入不定參數的function中,需以c_str()傳入wxChar*字串的pointer,才能在function中取得字串的內容。

// the parameter must be wxChar*
// -> please convert wxString by c_str() before push it
//    _T("") would be convert to wxChar*
// Ex: wxString s = _T("Falldog");
//     ComposeContent(2, s.c_str(), _T("'s blogger"));
wxString ComposeString(int count, ...)
{
    wxString res;
    va_list vl;
    va_start(vl, count);
    for(int i=0 ; i<count ; ++i)
        res += va_arg(vl,wxChar*);
    va_end(vl);
    return res;
}

30 8月 2012

[Code::Blocks] Compile Code::Blocks source code in Windows

Code::Blocks是一款出色的跨平台IDE,是用跨平台的語言wxWidgets所寫的,由於wxWidgets並不像Java一樣,有Virtual Machine,是可以build成原生的執行檔執行的,所以執行的速度會快很多。由於最近想寫看看Code::Blocks的PlugIn,所以就試著build CB的source code看看,用CB來build CB倒是挺有趣的。

23 8月 2012

[VisualStudio] Generate Assembly result file

VisualStudio在compile檔案過後,預設是不會產生assembly file的,但是有時候會想看看compile過後assembly code長怎麼樣,當project的Optimization有enabled的話,一樣的code在不同的Optimization level會有不一樣的結果,這就是VC對code優化處理。

要打開assember output的話,先進入Project Property Page(在project上點右鍵,選propertys)
以VS2008為例,在 Configuration Properties | C/C++ | Output Files
選擇 Assembler Output ,有一些選項可以選

  • Assembly-Only   (輸出.asm檔)
  • Assembly, Machine Code and Source (輸出.cod檔)
  • Assembly With Machine Code  (輸出.cod檔)
  • Assembly With Source Code  (輸出.asm檔)
可以選擇最詳細的Assembly, Machine Code and Source來看



最後就可以在指定的輸出路徑(ASM List Location)裡,找到各個檔案的*.asm or *.cod,打開來就可以研究一下裡面的assembly code了~

更多詳細的設定介紹 - MSDN - /Fa /FA

16 3月 2012

[Win32] Save Bitmap

Save Gdiplus::Bitmap
HRESULT GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    /*
    format support : 
        "image/png"
        "image/bmp"
        "image/gif"
        "image/jpeg"
        "image/tiff"
    */
    UINT  num  = 0;  // number of image encoders
    UINT  size = 0;  // size of the image encoder array in bytes

    GetImageEncodersSize(&num, &size);
    if(size == 0)
        return E_FAIL;  // Failure

    ImageCodecInfo* pImageCodecInfo = NULL;
    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if(pImageCodecInfo == NULL)
        return E_FAIL;  // Failure
    GetImageEncoders(num, size, pImageCodecInfo);
    for(UINT j = 0; j < num; ++j)
    {
        if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
        {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return S_OK;  // Success
        }
    }
    free(pImageCodecInfo);
    return E_FAIL;
}

void SaveBitmap(Bitmap* bitmap)
{
    // Get the CLSID of the JPEG encoder.
    CLSID clsid;
    GetEncoderClsid(L"image/jpeg", &clsid);
    
    bitmap.Save(L"C:\\test.jpg", &clsid, NULL);
}

04 8月 2011

[Python] Lazy initialization

在寫大型的Project時,應該都會遇到一種痛,就是AP開起來的速度"操級慢",很多人習慣在一開始就把一些用不到的變數initial起來,不但影響到AP launch的速度,也會讓memory吃得肥茲茲的。

所以就有人嘗試在一開始將變數initial成None,等到要用時再判斷是不是None,是的話再真正的initial這個變數。

不過這種作法,可能會讓code變得稍微複雜一點,參考一下別人的作法,其實有更好的方法來實作這種Lazy Initialization,就是用到Python的decorator+property!

12 4月 2011

[Python] 取得Python object的reference count

在Python的世界裡,每個變數都是一個object,而且每個object會有一個reference count去記錄被reference幾次,一但這個值變0時,這個object才會真正被delete掉。

[Python] 實作一個PriorityQueue 與 有pause, resume 功能的PriorityTaskThread

由於project是用Python2.5,要用到PriorityQueue,但是Python2.6以後才支援PriorityQueue,所以就想說寫個來試試。主要是改寫自Python原有的Queue class,繼承了原有的access blocking的feature,將原本的put改用insert與append,讓有相同priority的task能有先後之分。

07 4月 2011

[Python] Hook stdout後 print會出現 UnicodeDecodeError

在Python裡,字串的表達方式分為兩種,一種是常見的ansi string:"abc",另一種則是unicode:u"abc",而OS在秀出文字到window上時,其實都會轉換到使用者設定的code page後才秀出來的。簡單來說,繁體中文有一個對應的code page(cp950),簡體中文也有個對應的code page(cp936),如果一個unicode的字串參考錯誤的code page轉換出來的字串就有可能會變成亂碼了。

22 12月 2010

[emomeDDSMS] 下載emome上的備份簡訊 更新0.73

應觀眾要求,新增功能,輸出傳送簡訊的號碼與通訊錄的暱稱。
下載連結(按右鍵另存新檔):emomeDDSMS 0.73 (2010/12/22)
Change Log:
1. Add output phone number and nick name function - GetPhoneBook() and ConvertPhonelist()

使用說明,請參考前一篇文章。

28 9月 2010

[emomeDDSMS] 下載emome上的備份簡訊 更新0.72

因應emome網頁些許的更新與問題,emomeDDSMS也要稍作修改。
下載連結(按右鍵另存新檔):emomeDDSMS 0.72 (2010/9/28)
Change Log:
1. emome browse sms page changed, 'from' action changed to 'POST', modify related url actions.
2. Add ResetPage() mechanism for emome website issue, sometimes can't browse normal
3. Add description, suggest to download file to D disk

使用說明,請參考前一篇文章。