TAG

首都機能移轉 (2) 歌詞 (2) 靠北文 (40) 戲言 (30) 糟糕 (7) ACG (23) Assembly (2) Boost (2) C (31) C++ (69) CMake (4) CSIE (67) Debian (34) Design_Pattern (2) Django (1) Eclipse (1) en_US (13) FFmpeg (3) FoolproofProject (26) FreeBSD (2) Git (4) GNU_Linux (65) IDE (5) Java (11) JavaScript (19) KDE (15) Khopper (16) KomiX (3) Kubuntu (18) Life (1) Lighttpd (2) Mac_OS_X (2) Opera (1) PHP (2) PicKing (2) Programing (21) Prolog (1) Python (7) QSnapshot (2) Qt (30) Qt_Jambi (1) Regular_Expression (1) Shell_Script (7) Talk (98) VirtualBox (7) Visual_Studio (13) Windows (18) zh_TW (36)
顯示具有 C++ 標籤的文章。 顯示所有文章
顯示具有 C++ 標籤的文章。 顯示所有文章

2012年7月15日 星期日

Garbage Collection (1)

這篇只是介紹比較知名的方法,預計之後還會再發一兩篇討論 C++/Qt 的回收手法。

2012年5月12日 星期六

How to debug a program which grabs X11 input events

最近在做的抓圖程式, 因為要在非 focus 狀態也能接收到抓圖要求, 必須取得所有的輸入事件控制權.
但如果必須要在這種地方下中斷點, 因為 X11 所有的輸入都被搶走了, 你無法操作 gdb.

2010年11月25日 星期四

你永遠料不到自己有多蠢

最近某個作品在開啟檔案時會不定期當掉 ... 原本一直找不出原因, 直到我在除另一個不相關的 bug 時發現這個函式:
const char * fromURI( const QUrl & uri ) {
    QByteArray tmp( uri.toString().toUtf8() );
#ifdef Q_OS_WIN
    if( uri.scheme() == "file" ) {
        tmp.prepend( 'w' );
    }
#endif
    return tmp;
}

2010年4月2日 星期五

Converting literal

為了避免荒廢,來貼個廢文充數好了。
上一篇有提到 string literal 的問題,這是把文字轉成 hex 的 C 程式,不過要用 C99 去編譯才行。
#include <stdio.h>

int main() {
  for( char tmp[1024]; fgets( tmp, sizeof( tmp ), stdin ) != NULL; ) {
    for( unsigned char * c = tmp; *c; ++c ) {
      if( *c == '\n' ) {
        printf( "\n" );
      } else {
        printf( "\\x%02X", *c );
      }
    }
  }
  return 0;
}

2010年3月14日 星期日

Using UTF-8 literals in source code

直接在 code 裡打 UTF-8 字元在有的 IDE 會無法辨識,像是 Visual C++ 2005 和 2008 堅持使用 locale 的編碼來解讀 source,導致換 locale 就會編譯失敗。
這種時候沒什麼有效的解決方法,就是用 hex escape 字元啦 ...
/* 正體中文 in UTF-8 */
const char * utf8 = "\xE6\xAD\xA3\xE9\xAB\x94\xE4\xB8\xAD\xE6\x96\x87";
很煩,很難讀,不過至少所有的字元都保證在 C / C++ 的標準字元集裡;只是最好在旁加上註解說明那應該是什麼字,否則很難維護。

2009年11月29日 星期日

Array IS NOT pointer

呣,其實我大一的時候也有這種觀念,畢竟那時 pointer 還是個陌生的怪物,那還是個「如果你不會傳 array 就宣告成 global」的時代。
基本上 C 的 array 實在不怎麼討喜,包括它的「陣列大小一定要跟在陣列名稱後面」這種鳥語法,如果再加上 function pointer 那可真是醜斃了。之所以 array 經常和 pointer 混為一談,最大的原因應是 array 會被隱式轉型[?]為 pointer,且 array 變數本身的值就是 array 第一個元素的位址。這讓你可以把陣列丟入如下的函式裡:
void f1( const int * array );
呃,那二維陣列呢?
void f2( const int * * const array );
因為並不存在多維陣列對 pointer 的隱式轉換,因此你無法直接丟進去。
接下來要談談 array 和 pointer 有什麼不同。
最顯著的性質是,array 變數本身是唯讀的,它無法再被賦值,其代表的空間也無法被手動釋放,而 pointer 值則可以變動,指向的內容可能可以被手動釋放;這也是 pointer 令新手感到易混淆的地方,因為它同時有資源的持有者以及迭代性質。
此外,pointer 可以被取址,但是 array 的址和它自己一樣,也就是陣列開始的第一個位址:
int cla[1];
printf( "%p %p\n", cla, &cla );    // the same
另一個較為有用的不同點是,array 可利用 sizeof 求大小,而 pointer 就只是個 pointer。
int8_t a[10];
sizeof( a ); // 10
int8_t * b = a;
sizeof( b ); // 4 or 8, depends on your compiler
那如果你很希望陣列在傳入函式後還是個陣列,C++ 的 template 可以幫得上忙:
template< typename T, std::size_t N >
std::size_t getByteLength( const T ( & array )[N] ) {
    return sizeof( array );
}

// how to use:
int32_t tmp[4];
getByteLength( tmp );  // will return 16
坦白說,我不是很清楚為什麼一定要用 reference to array,不過你的確可以用這個 template function 傳 array。再多維也可以:
template< typename T, std::size_t N, std::size_t M >
std::size_t getByteLength2( const T ( & array )[N][M] ) {
    return sizeof( array );
}
以此類推。

2009年11月5日 星期四

A way to use C++ object in C callback

前幾天在用 libFLAC 的時候[?],它要求 client 註冊一個 callback 給它,prototype 長這樣:
typedef FLAC__StreamDecoderWriteStatus
(* FLAC__StreamDecoderWriteCallback)
(const FLAC__StreamDecoder *decoder,
const FLAC__Frame *frame,
const FLAC__int32 *const buffer[],
void *client_data);
看起來很複雜,其實不會,就是個 function pointer 的 typedef 而己[?]
可以看到最後一個 void * client_data 是用來接受 client 的資料用的,先接 void * 再轉成自己要的型別,算是 C 的老手法了。
Well, 在 C++ 上使用時就沒有那麼簡單。第一個問題是 member function 需要實體才能使用。
簡單一個想法是宣告一個 struct,把實體和 pointer to member function 包起來,再傳給這個 callback function。不過一來這有點麻煩,二來你不能呼叫用 protected 或 private 修飾的 members。
沒關係,我們有 friend!
嗯,不好意思,這的確是可以動,不過真的很爛。
還好我們還有另一顆子彈,就是 static member function。static member 不需要實體,且 member function 可以存取 class 內所有 member,這樣就一次解決了兩個問題。
所以我們的 callback 會長這樣:
static FLAC__StreamDecoderWriteStatus
FlacReader::writeCallback_
(const FLAC__StreamDecoder *decoder,
const FLAC__Frame *frame,
const FLAC__int32 *const buffer[],
void *client_data) {
    FlacReader * self = static_cast< FlacReader * >( client_data );
    // blah blah
}
client_data 那裡傳 this 就好。
不要譴責我沒用 dynamic_cast,我百分之百確定 client_data 是 FlacReader 好嗎?

2009年9月18日 星期五

如何讓你的程式更難理解(5)

int uglystrieq( const char * l, const char * r ) {
    while(*l&&*r&&(*l++|32)==(*r++|32));return *l--||*r--||(*l|32)!=(*r|32);
}
Compare the equivalence of two strings. Case insensitive.
[Edit]
This implementation while crash when passing a 0-lengthed string. Another version:
int _(const char*l,const char*O) {
    return ((*l|32)-(*O|32))?1:*l?_(l+1,O+1):0;
}

2009年8月1日 星期六

C++ 的多緒安全性

簡單的說,因為標準給編譯器優化的限度太寬鬆,導致編譯器可以很大程度地調換指令的順序,因此 critical section 也有可能無法完全包好。不少人以為 volatile 可以禁止優化,從而確保正確順序,但其實它只保證單緒的順序,多緒的狀況還是無法保證;連鬼才 Andrei Alexandrescu 都在他的神作 Morden C++ Design 裡犯了這個錯誤(我也不認為他示範的 Singleton 真的有 thread-safe)。
也許等 C++0x(呃,可能會變成 C++1X) 釋出之後,可以帶給我們更複雜的 C++ 吧。XD

2009年5月2日 星期六

Compile C or C++ code from stdin

偶而你會懶得存檔,因此有方法可以直接編出來:
# for C
gcc -xc -
# for C++
g++ -xc++ -

# for example
echo 'main(){puts("Hello world!");}' | gcc -xc - && ./a.out

2009年4月15日 星期三

Export DLL symbols to LIB

用 gcc 如果要發佈成 dll,只要編譯器加點選項,就可以發佈給別人連結了。但是 Visual C++ 卻要在每個 symbol 上加上關鍵字 __declspec(dllexport) 才會匯出到 lib,然後才能連結。
__declspec(dllexport) void blah();
class __declspec(dllexport) Blah {};
不管怎麼說,微軟的確是這方面的天才。

2009年2月9日 星期一

該死

我實在不知道該怨恨誰了,就讓我恨天吧...(?)
故事的開頭,是在我想把程式port到Windows的時候發生的。
首先我遇到了TR1和C99名稱缺省的問題,沒關係,我知道每次都要跟上標準很累,VC沒有<cstdint>,gcc也沒實作std::tr1::regex,一人一次很公平,打平了,還好我還有Boost,不怕你。
然而沒想到魔王其實不在這裡,而是Unicode。
先簡單的介紹一下一般處理系統字串的方法好了。
大家都知道早期各國為了顯示自己的文字,定了各種了不起的編碼方式來對應字型,Big5的許功蓋就是這段歷史下的偉大人物,大概比踢牙齒老奶奶這位史詩級人物還要再個高一級左右。
夫天下大勢,分久必合合久必分,某個大有為的組織看不慣這種戰國亂象,於是制定了Unicode的編碼標準,以對應全人類的偉大文化產物,又生出了各種對應Unicode的編碼方式,希望能夠平息亂碼之亂。要注意的是,編碼標準和編碼方式不同,每個文字在Unicode裡只有一種編碼標準,再根據各種不同的編碼方式,比方說UTF-8或UTF-16,UCS4等編成不同的編碼。
那麼我們在程式裡是怎麼處理各種不同的輸入和輸出呢?
最常用的方法就是,把輸入字串解碼成Unicode字串,如此一來就可以在程式裡方便地處理字串,在輸出時再編碼成需要的輸出字串。
那要怎麼存Unicode字串呢?C和C++都提供了wchar_t來存寬字元,你可以用它來存放Unicode化過的字元。但是有趣的地方也在這裡,Windows和其他系統的wchar_t的寬度是不一樣的,Windows是2 bytes,Linux等是4 bytes,因此在Windows上你可能要選擇UTF-16,而在Linux上要用UCS4。
這還不是最糟糕的。
Linux的系統函式都沒有提供wchar_t的版本,因為現在系統上的編碼都是用UTF-8,就算用locale的編碼也不會漏失字元。
但是Windows就提供了另一套w開頭的API,以提供wchar_t的版本,同時系統函式分成兩系,一是W結尾,使用wchar_t,一是A結尾,使用char,而且要編成本地編碼。
於是當某個你碰不到的程式碼內部使用fopen時,在Windows上你一點辦法都沒有,根本不能讀取non-ascii的路徑。

2008年8月18日 星期一

部置Visual C++程式

翻成"部署"還真是怪怪的....
我看就很麻煩,而且還失敗很多次....果然是DLL hell。

2008年7月31日 星期四

如何讓你的程式更難理解(3)

char * strcpy( char * dst, const char * src ) {
    char * tmp = dst;
    while( *dst++ = *src++ );
    return tmp;
}

2008年7月23日 星期三

Self initialization

int i = i;
這樣做gcc竟然沒問題....
再來看看C++的例子:
struct Test {
    Test() : i_( 0 ) {
        std::cout << "Default constructor" << std::endl;
    }
    Test( const Test & rhs ) : i_( rhs.i_ ) {
        std::cout << "Copy constructor" << std::endl;
    }
private:
    int i_;
};
int main() {
    Test a( a );
    return 0;
}
可以看到只印出一個Copy contructor出來....而內部的變數是未定義的。

2008年3月31日 星期一

Debug Assembly Language With GDB

gcc -S blah.c                   # if you want generate from C
as blah.s --gstabs -o blah.o    # --gstabs enables debug flags
gcc blah.o -o blah              # link object file
gdb blah                        # now you can debug it