Sean's Note: C_CPP
顯示具有 C_CPP 標籤的文章。 顯示所有文章
顯示具有 C_CPP 標籤的文章。 顯示所有文章

2014年3月27日 星期四

Running C/C++ on Android with NDK

需要準備的環境

  1. Eclipse + Android SDK: 基本的 Android 開發環境
  2. Android NDK: 讓 Android 能透過 JNI 去執行 C/C++ 語言的必要套件
  3. Eclipse NDK: Eclipse 的 plugin 套件,方便管理與建立 NDK 的專案
    Work with: https://dl-ssl.google.com/android/eclipse/
    安裝好之後要設定 Android NDK 的路徑:
    Window -> Preferences -> Android -> NDK -> NDK Location:
  4. Eclipse CDT: Eclipse 的 plugin 套件,可以在 Eclipse 上管理與開發 C/C++ 專案
    Work with: http://download.eclipse.org/tools/cdt/releases/juno (For Juno)
    Work with: http://download.eclipse.org/tools/cdt/releases/kepler (For Kepler)
  5. Cygwin: 用來編譯 C/C++
    Ref: http://blog.csdn.net/javatiger427/article/details/6115693
註1: NDK(Native Development Kit)
註2: CDT(C/C++ Development Tooling)

新建一個專案


步驟可參考下列網址:
http://www.pupuliao.info/2013/05/%E5%9C%A8eclipse%E9%80%8F%E9%81%8Ejni-%E8%B7%91cc-for-android-hello_world%E7%AF%87/

文中設定 Builder 的部分可略過,只是為了存檔的同時也能重新自動建置。

而且遇到有空白字元的路徑更為麻煩,可將文中 Arguments 的部分換成如下:

--login -c "cd /cygdrive/d/sample &&  rm -r obj && /cygdrive/c/Progra~1/Android/android-ndk-r9d/ndk-build"

另外,我們也可以透過按下小鎚子的圖示來手動建置。

除錯


除錯時要將 Project -> Properties -> C/C++ Build -> Builder Settings -> Build Command:

加上 ndk-build NDK_DEBUG=1,建置時才會產生除錯所需要的檔案。

在這之後可能會遇到兩個問題:
  1. 無法在 .c 或 .cpp 檔上設置中斷點?
    Run -> Breakpoint Types  -> C/C++ Breakpoints
  2. 設完中斷點後,卻沒有停在中斷點上?
    No symbol table is loaded. Use the "file" command.
    由於 GDB debugger 需要一點時間運算,而 GDB 可能還沒載入 Library 的 Symbol,
    如果中斷點設得太早可能會被忽略,
    解決的辦法請參考:
    http://www.codeproject.com/Articles/493043/Why-your-Android-NDK-breakpoints-might-fail-and-ho

2014年3月26日 星期三

Develop C/C++ with Eclipse CDT

Setup

連結中的網址講的還蠻詳細的:
http://www3.ntu.edu.sg/home/ehchua/programming/howto/eclipsecpp_howto.html

唯一要補充的是,如果沒有加上 C:\cygwin\bin 或 C:\cygwin64\bin 到系統的環境變數中,

會引發下列錯誤:
  1. 在 include 的地方會有 "Unresolved Inclusion Error"。
  2. 用 Eclipse 的 Run 去執行時,會跑不起來。
  3. 直接跑  exe 執行檔,會跳出找不到 cygwin1.dll 的錯誤視窗。
如果想避免新加的環境變數影響到其他程式,替代的方法是

在 Window -> Preferences -> C/C++ -> Make -> New Make Projects 時指定 PATH 的路徑: 

Debug

想在 CDT 的環境下 debug,需要對  Window -> Preferences -> C/C++ ->
Debug -> Common Source Lookup 做一些設定:


2013年3月26日 星期二

Macro # 和 ## 的用法

使用 # 可以把巨集引數變為一個字串,而 ## 則把兩個巨集引數串接在一起。

例如:
#define STR(s) #s
#define EXP(a,b) int(a##e##b)

printf ("Number %s\n", STR(655.3)); // Number 655.3
printf ("Number %s\n", EXP(5, 2));  // int(5e2), Number 500

2013年2月18日 星期一

今天遇到了一個跟 namespace 有關的蠢問題

// A.cpp
namespace SEAN
{
    static int num;
}

// B.cpp
#include "A.h"

int num = SEAN::num; // 這行一直跑出 error C2589: '(' : illegal token on right side of '::'

搞了很久才注意到 SEAN::num 是定義在 A.cpp 而非 A.h,

想要用就要定義在 A.h 裡。




2012年10月24日 星期三

[STL] 位移 List 的 Iterator

平常我們會使用 List 來記錄一些 data,例如:
list<int> mylist;

for (int i=0; i<10; i++) mylist.push_back (i*10);

並將 Iterator 指向開頭來走訪 data。

list<int>::iterator it = mylist.begin();

想要取得下一個元素時,可以使用 *it++ 前進一步。


那想要取得第 N 個元素呢?


呼叫 *it++ N 次嗎?


於是我們有了 advance 函式幫我們快速的移動到第 N 個元素:

advance (it, N-1);

2012年6月26日 星期二

不要將 vector 做為參數傳遞至 DLL

最近用了 STL 的 vector 當作 DLL 裡的函式參數,讓 EXE 建立的 vector 給 DLL 做事,

結果發現一直莫名其妙的 Crash,原來 EXE 和 DLL 會有各自的記憶體存放靜態成員,

而大部分的 STL 物件類別都使用靜態成員資料(Static Data Member),所以就會造成 


Access Violation, Data Lost 甚至於 Crash。


參考資料:
http://www.cnblogs.com/mysunnyday/archive/2011/08/23/2150279.html
http://support.microsoft.com/default.aspx?scid=KB;en-us;q172396

2012年6月16日 星期六

[C/C++] public/protected/private 繼承

class A
{
      public:
      void print() {printf ("print() From class A\n");};
      protected:
      void print2() {printf ("print2() From class A\n");};
      private:
      void print3() {printf ("print3() From class A\n");};
      
};

class PublicB : public A
{
      public:
      int print() {printf ("print() From class B\n"); print2();};  // Redefine
      /* 注意: protected 的 print2() 雖被繼承下來, 但不為外人所用 */
      /* 注意: private 的 print3() 並沒有被繼承下來 */
};

class ProtectedB : protected A
{
      public:
      /* 注意: public 的 print() 雖被繼承下來, 但此時已變為 protected */
      /* 注意: protected 的 print2() 雖被繼承下來, 但不為外人所用 */
      /* 注意: private 的 print3() 並沒有被繼承下來 */
};

class PrivateB : private A
{
      public:
      void myPrint() {print(); print2();};      
      /* 注意: public 的 print() 雖被繼承下來, 但此時已變為 private */
      /* 注意: protected 的 print2() 雖被繼承下來, 但此時已變為 private */
      /* 注意: private 的 print3() 並沒有被繼承下來 */
};

int main()
{
    A clsA;
    clsA.print();
    //clsA.print2(); // Compiler Error! print2() is protected.
    
    PublicB clsB_pub;
    clsB_pub.print();
    //clsB_pub.print2(); // Compiler Error! print2() is protected.
    
    ProtectedB clsB_pro;
    //clsB_pro.print(); // Compiler Error! print() is protected.
    //clsB_pro.print2(); // Compiler Error! print2() is protected.
    
    PrivateB clsB_pri;
    clsB_pri.myPrint();

    system("pause");
}
  1. 首先,繼承的概念是,只有 public 和 protected 的成員函式或變數會被繼承下來,除了建構式 (Constructor)、解構式 (Constructor) 和 Copy Constructor 除外,還有 private 也不會。
    • public: 所有人都能使用。
    • protected: 只有自己和兒子 (Derived Class) 可以使用,外人不能使用。
    • private: 只有自己可以使用, 兒子 (Derived Class) 和外人皆不能使用。
  2. 倘若 B 以 public 方式繼承了 A,則存取修飾字 (Access Specifier) 保持相同,規則同 1。
  3. 倘若 B 以 protected 方式繼承了 A,則 A 的 public 和 protected 成員被以 protected 方式繼承,所以範例中的 Line:48, 49 則發生編譯錯誤,因為  protected 成員不為外人所用。
  4. 倘若 B 以 private 方式繼承了 A,  則 A 的 public 和 protected 成員被以  private 方式繼承 ,僅自身可使用 Line:31。

2012年6月7日 星期四

class 中的 const 成員函式

const 函式主要定義為不能改變 class 中的變數。
此外,const  物件 只能引用 const 函式。


class A
{
private:
      int number;
public:
      A(int value){number=value;};
      void const_f(void) const {/*number=1;*/}; // 不能對成員變數賦值
      void nonconst_f(void){number=1;};
};

int main()
{
    const A a(1);
    a.const_f();
    a.nonconst_f(); // 編譯錯誤: const 物件只能引用 const 函式
    return 0;  
}

2011年12月16日 星期五

[Debug] printf


撰寫程式時,我們常會透過 printf 來 debug,但 release 的時候又

需要把這些 printf 註解掉,造成了不少麻煩。這時我們可以利用

Maco 定義我們的 printf 函數,當有定義 _DEBUG_ 時才印出東西,

否則不作任何事,_DEBUG_  就像一個開關一樣。

範例如下:

#define _DEBUG_

#ifdef _DEBUG_
  #define DPRINTF(...) { printf(__VA_ARGS__); }
#else
  #define DPRINTF(...)
#endif

DPRINTF ("123\n");
DPRINTF ("%d\n", 123);

2011年11月23日 星期三

[DEBUG] _RPT & _RPTF


Visual C++ 提供了 _RPT 和 _RPTF 巨集來幫助使用者除錯,

其功能類似於 printf,但僅在 Debug 設定下會印出字串,

Release 設定下則會自動刪除。其可印出呼叫該巨集的程式檔案名稱與行數。

例如 :

_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);

_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);

_RPT0(_CRT_WARN, "Test.\n");

// Output
Test

_RPT1(_CRT_WARN, "Test %d.\n", 1);

// Output
Test 1

_RPTF0(_CRT_WARN, "Test.\n");

// Output
d:\win32\assert\assert\assert.cpp(54) : Test

_RPTF1(_CRT_WARN, "Test %d.\n", 1);

// Output
d:\win32\assert\assert\assert.cpp(54) : Test 1


有無 F 差在要不要印出檔案名稱與行數,而數字代表要代入的參數個數,最多到 4 。


[DEBUG] _ASSERT & _ASSERTE

Visual C++ 提供了 _ASSERT 和 _ASSERTE 巨集來幫助使用者除錯,
其功能類似於 printf,但僅在 Debug 設定下會印出字串,
Release 設定下則會自動刪除。其可印出一布林運算式的結果。
用法例如 :

_ASSERT(3 == 3);
 // Output
d:\win32\assert\assert\assert.cpp(53) :

_ASSERT(3 == 2);
 // Output
d:\win32\assert\assert\assert.cpp(53) : Assertion failed!

_ASSERTE(3 == 3);
 // Output
當條件成立時不印出任何字串

_ASSERTE(3 == 2);
 // Output
d:\win32\assert\assert\assert.cpp(53) : Assertion failed : 3 == 2


記得要先設定為 _CRTDBG_MODE_FILE,才會顯示在 console 上,
否則預設為跳出視窗( _CRTDBG_MODE_WNDW )。

_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

2011年9月13日 星期二

[VC] 用 dumpbin 來看 DLL 檔

在 Visual Studio 裡提供了 dumpbin 工具,可以用來查看
DLL 檔提供了哪些函式,dumpbin.exe 的位置於 :
C:\Program Files\Microsoft Visual Studio 8\VC\bin
如果執行時出現找不到 mspdb80.dll 時,
將 C:\Program Files\Microsoft Visual Studio 8\Common7\IDE 
加到系統環境變數的 Path 裡。

2011年3月15日 星期二

[C/C++] extern 的用法

想要宣告一全域變數讓其他文件 (.c 或 .cpp) 共同使用,

必須在型態前加上 extern, 表示變數在文件之外, 如 :

int data; // 宣告在 file1.c

extern int data; // 則必須宣告在 flie1.h

當 file2.c 要使用變數時, 只要 include file1.h 即可,

不必再宣告該變數.

2010年12月20日 星期一

[C/C++] 動態宣告二維陣列

// ==========================

// C Style

// ==========================

int **p;
int i;


// 欲配置成 p[10][3]

p = (int **)malloc(10 * sizeof(int *));
for (i = 0; i < 10; i++){
    p[i] = (int *)malloc(3 * sizeof(int));

....

// 使用完後釋放記憶體空間
for (i = 0; i < 10; i++)
    free(p[i]);

free(p); 





// =========================

// C++ Style

// =========================

int **p; // 二維動態

// 欲配置成 p[10][3]
p = new int* [10];
for (int i = 0; i < 10; i++){
    p[i] = new int [3];

...


// 使用完後釋放記憶體空間
for (int i = 0; i < 10; i++)
    delete [] p[i];

delete [] p; 


int (*p)[3]; // 一維固定一維動態

// 欲配置成 p[10][3]
p = new int[10][3];
for (int i = 0; i < 10; i++){
    p[i] = new int [3];

...


// 使用完後釋放記憶體空間
delete [] p; 

2010年12月17日 星期五

[C/C++] 在Dev-C++安裝OpenCV2.0

(1)下載 OpenCV-2.0.0a-win32.exe
(2)安裝OpenCV2.0在C:\OpenCV2.0
(3)在DEV 工具/編譯器選項/編譯器 的編譯器設定組態中新增編譯器設定(加號按鈕)並命名為"OpenCV2.0"
(4)在連結器命令列中加入以下命令(前面框號要打勾)
-llibcxcore200 -llibcv200 -llibcvaux200 -llibhighgui200 -llibml200
(5)在DEV 工具/編譯器選項/目錄/二進位檔 加入:
C:\OpenCV2.0\bin
C:\Dev-Cpp\Bin
C:\Dev-Cpp\libexec\gcc\mingw32\3.4.2
(6)在DEV 工具/編譯器選項/目錄/函式庫 加入:
C:\OpenCV2.0\lib
C:\Dev-Cpp\lib
(7)在DEV 工具/編譯器選項/目錄/C引入檔 加入:
C:\OpenCV2.0\include\opencv
C:\Dev-Cpp\include
(8)在DEV 工具/編譯器選項/目錄/C++引入檔 加入:
C:\OpenCV2.0\include\opencv
C:\Dev-Cpp\lib\gcc\mingw32\3.4.2\include
C:\Dev-Cpp\include\c++\3.4.2\backward
C:\Dev-Cpp\include\c++\3.4.2\mingw32
C:\Dev-Cpp\include\c++\3.4.2
C:\Dev-Cpp\include
(9)在C:\OpenCV2.0\include\opencv中找到cxoperations.hpp檔
(10)找到檔中第66行部分程式碼如下
#else
#include <bits/atomicity.h>
#if __GNUC__ >= 4
(11)將它改成如下程式碼並儲存
#else
#include <bits/atomicity.h>
#if __GNUC__ >= 4 || __MINGW32__
(12)每次開新的專案必須在專案中選擇新建的編譯器設定(OpenCV2.0)


轉載自: http://yester-place.blogspot.com/2008/06/dev-copencv.html

2010年11月24日 星期三

[C/C++] 常見的型態運算錯誤

char a = 200;
char b = 200;
int c;

c = a + b;
c 會是多少呢?

答案是 -112 而不是 400
因為 a 和 b 實際上都為 -56,所以 -56 + -56 = -112

2010年10月17日 星期日

[C/C++] structure and class

Class is equal to structure plus member function, but a C++ structure can do any thing a class can do!
Only their default access level are different.
Structure's fields are public by default.
Class fields are private by default.

2010年10月16日 星期六

[C/C++] Default Arguments

在 C++ 裡,函式中的參數是可以在定義的時候給初始值的 (C 不支援)。
// definition
void a (int b, int c = 1, int d = 1);

int main ()
{
    a(1, 2, 3);
    a(1, 2);
    a(1);
}

// implementation
void a (int b, int c, int d)
{
    ...
}

2010年10月6日 星期三

[C/C++] Data structure alignment

通常 structure 中都會以 size 最大的成員作為 alignment 的單位,以提高運算效率。
以 struct A1 來說,最大為 double 所以 alignment 的單位為 8 bytes,
sizeof( struct A1) 就會是 4 + 4 + 8 + 8 = 24 bytes。
sizeof( struct A2) 就會是 4 + 4 + 8 + 1 + p(7)  + 8 = 32 bytes,
padding 了 7 bytes。
struct A1
{                            
    int a;  
    char b[12];
    double c;        
};

struct A2
{                              
    int a;    
    char b[13]; 
    double c;          
};
使用虛擬指令 #pragma pack(n) : 編譯器將按照 n bytes 對齊。
使用虛擬指令 #pragma pack() : 取消自定義對齊方式。
#pragma pack(2)
struct D
{                            
    int a;  
    char b;        
};
#pragma pack()
如果指定的 n 大於 structure 中成員的最大 size 將不起作用,仍依 size 最大的成員
進行對齊。sizeof( struct D) 就會是 4 + 1 + p(1) = 6 bytes。

2010年9月6日 星期一

[C/C++] C++ 的 int 轉成 string class

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

string int2str(int &);

int main(void) {
  
  int i = 1200;
  string s;
  s = int2str(i);

  cout << s << endl;
}

string int2str(int &i) {
  
  string s;
  stringstream ss(s);
  ss << i;

  return ss.str();
}