2011年6月7日 星期二

porting tslib (abstraction layer for touchscreen) to ARM Platfrom

Step by Step:
my environment:
OS: Ubuntu 10.04
Cross-compiler:
  - CC   = linux-arm-gcc (4.1.2)
  - CXX = linux-arm-g++ (4.1.2)

  1. Download tslib source code
    • download tslib tar or zip file from http://tslib.berlios.de/
    • my download file version is named kergoth-tslib-1.0-94-gd4073fe.zip
  2. Install dependency libraries
    • sudo apt-get install m4 autoconf automake libtool
  3. set tslib install path
    • export PREFIX=/home/myname/tslib/BUILD 
      #set INSTALL PATH by your choice
  4. execute autogen.sh
    • ./autogen.sh
    • After this command finished, it generates configure file for tslib.
  5. configure tslib
    • ./configure --build=i386-linux --host=arm-linux --target=arm --prefix=$PREFIX ac_cv_func_malloc_0_nonnull=yes
  6. make; make install

2011年6月2日 星期四

[C++] The significance about - extern "C"

extern "C" 是C++特有的組合關鍵字,在C裡並沒有這個的組合,僅有extern這個關鍵字!

為什麼C++會需要這樣的關鍵字組呢? 原因是C++它有一個複載(overloading)的功能,也就是說同樣的函式名稱可以有多個定義只要參數簽名不同即可。
比如說C++裡可以有以下的二個宣告


bar(int i, int j);

bar(double i, double j);

這二個函式都是同樣的名字叫foo,僅參數型式不同。然而在C語言裡是不被允許的! C++是如何處理這同名的函式呢? 其實他在編譯時會偷偷的把這二個函式名變成不同的名字,舉例來說bar(int i, int j)可能會被改成_bar_int_int(每種compiler產生不太一樣),而另一個則被改成_bar_double_double。這技術稱 Mangling。

問題來了! 當我們希望C++不要偷換函式名時該怎麼辦? 於是就有了extern "C" 這個關鍵字組出現了。這個字組就是請C++不要自己又偷天換日,請它保留原名。所以當我們宣告一個函式如下時:

extern "C" bar(int i, int j);

編譯器就不會把bar變成_bar_double_double。

實際使用的注意事項:

1/ 當C++使用C的函式庫(library)時,C++不能直接套用C的header檔。因為他會把header裡的宣告給mangleing了。所以他必須使用如下:

extern "C"
{
#include "C_LIB.h" //C_LIB 是由C語言所寫的。
}

2/ 相反的,在C語言的編譯器裡若要使用由C++所寫出來的C函式庫,那麼也不能直接的使用C++的header檔。因為此header檔必然存在 extern "C" 這個關鍵字組,而這字組C語言是不認識的。所以必需要把C++的header檔裡的extern "C" { } 移除後才可以讓C編譯器使用。

  • 注意事項


  • 一組多載函數中, 只能有一個函數被指明為 "extern C", 因為符號修飾後的關係, ex:

    void abc(int);
    "extern C" void abc(char);
    "extern C" void abc(float);
    

    使用 C 方式的修飾符號是 _函數名,因此是 _abc, 所以當第2組指明 "extern C" 也是 _abc 那麼兩組 C 函數的符號就重複了,此檢查在函數的多載就可以,但是同一個 scope 中函數沒有多載化就無法檢查出,更確切的說,"extern "C" 不受 namespace or class 修飾的影響, 因此同一編譯單元中只能有一個同名函數為 "extern C", 否則會有錯誤 ,ex:

    namespace N
    {
    extern "C" void abc(){} // _abc
    
    }
    
    extern "C" void abc(){} // _abc
    


    編譯時產生相同符號 _abc 函數定義故錯誤,由於 extern "C" 不受限於 namespace 的修飾因此將產生一個有趣現象也就是宣告和定義可以在不同的 namespace 出現。語法層面上的檢查就如同一般,而當語法檢查通過後產生符號時,extern "C" 的定義其符號不帶有 namespace 的修飾;同樣的,呼叫者其符號也不帶有 namespace 的修飾,ex:


    namespace Foo
    {
    extern "C" void abc() {} //有定義, 生成符號時, 不受限於 namespace Foo 修飾故符號為 _abc
    }
    
    namespace Bar
    {
    extern "C" void abc(); //純宣告 
    }
    
    int main()
    {
    Bar::abc(); //函數呼叫, 生成符號時, 不受限於 namespace Bar 修飾故符號為 _abc, 事實上鏈結到 ::Foo::abc()
    }
    

    還有下面如此鏈結錯誤的狀況:
    由於extern "C" 沒有多載功能,不論是 void abc() 或是 void abc(int a) 都將被以 _abc 來做為函式名稱,這是極度危險的.


    1.c
    extern "C" void abc();
    int main()
    {
    abc();
    }
    

    2.c
    #include
    extern "C" void abc(int a)
    {
    printf("%d",a);
    }
    

    當 1.c 和 2.c link 時可以,因為 c 沒有將參數名稱當作函式修飾名稱的一部分,故也就沒有多載,將 "C" 拿掉 link 時就會錯誤,因為會以 c++ 的方式來編譯。

    資料來源:C++中關於extern "C"的意義

    2011年4月19日 星期二

    Call by value , Call by pointer , and Call by reference

    • Call by Value
      • 參數會在函式中建立一個獨立的物件
      • 不論在函式中如何改變這個參數的值,都不會影響呼叫端的物件
      • 在該函式結束之後,所有的臨時物件都會清除,包括 call by value 所產生的參數
      int main() { 
          int x = 5; 
          foo(x); 
      }
      
      void foo(int y) {    // 建立一個新的物件等同於傳入的物件
          y++;    //不會改變到原呼叫端的物件
      }
      
    • Call by Pointer
      • 參數不會建立物件的複本
      • 以物件的產生、呼叫的成本考慮,傳參考與傳指標是十分類似。但傳指標與傳參考最大的分別是,參考是常數,而指標是變數
      • 因此這個指標可以指向另一個位置,另一個更明顯的分別是所有的陣列傳遞都是以傳指標的方式達成
      int main() {
          int a = 5;
          int *x;
          x = &a;
          foo(x);
      }
      
      void foo(int *y) {   // 建立一個指標指向傳入物件的記憶體位置
          (*y)++;    // 修改此*y就是修改main的*x
          int b = 9;
          int *c;
          c = &b;
          y = c;    // Thinking:compare with " *y = *c " here, how about the variables in main()?
      }
      
    • Call by Reference
      • 參數不會建立物件的複本,它只會建立一個指向呼叫端物件的參考
      • 所以如果在函式中改變這個參數的內容(先決條件是這個參數未被宣告為 const),就會改變呼叫端參數的內容
      • 特別要注意的是,Call by reference的方式,一定要在初始化時就有指向的實體,而且不能改變
    int main() { 
        int x = 5; 
        foo(x);    // 不用加& 
    }
    
    void foo(int &y) {    // 建立一個參考指向傳入物件的記憶體位置
        y++;    // 修改此y就是修改main的x,無法改變y所指向的記憶體位置
    }