發表文章

目前顯示的是有「C or C-plus-plus」標籤的文章

C/C++查閱引用(include)或使用巨集(macro)後編譯有問題的程式碼

圖片
為什麼需要查閱 C/C++引用(include)或使用巨集(macro)編譯出錯的程式碼,因為使用巨集編譯時發生的錯誤訊息提示的程式碼行數,往往不是原始碼(source code)中看到的行數。 在學習與除錯的時候總覺麻煩,下面就展示該如何查閱引用/使用巨集後的程式碼。

解決編譯C的function declaration isn’t a prototype

最近遇到的一個小問題,因為很容易忘記所以紀錄一下 test_abc.c:151:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]  static void init_module();  ^ 解法: 因為我已經寫了prototype,只是function沒有參數的話要多寫void,改成下面這樣就ok了 static void init_module(void);

小程式:從列表中移除

來源資料, 只看第一個 1 2 3 2 2 3 3 2 3 4 2 3 要刪除的內容 1 3 結果會得到 2 4 使用方法 process test.txt rmlist.txt result.txt debug原始載入資料 process test.txt rmlist.txt result.txt 1 debug載入資料第一欄 process test.txt rmlist.txt result.txt 2 #include <vector> #include <iostream> #include <string> #include <fstream> #include <algorithm> #include <sstream> using namespace std; int DEBUG = 0; string outpath = "result.txt"; int main(int argc, char** argv) {     cout << argc << endl;     if (argc <= 2) return -1;     cout << "long list:" << argv[1] << endl;     cout << "remove list:" << argv[2] << endl;     if (argc > 3) outpath = argv[3];     cout << "output file:" << outpath << endl;     if (argc > 4) DEBUG = atoi(argv[4]);     ifstream rdf(argv[1], ifstream::in);     ifstream ...

C格式化輸出入整理

printf格式化輸出 "%c" 字元 "%d"和"%i" 有號整數 "%u" 無號整數 "%o" 8進位的無號整數 "%#o" 8進位的無號整數,前面會帶0 "%x" 16進位的無號整數 "%#x" 小寫16進位的無號整數,前面會帶0x "%#X"  大寫16進位的無號整數,前面會帶0x "%p" 印出(void*)指標位址 "%f" float浮點數,若為科學表示法會用小寫顯示 "%F" float浮點數,若為科學表示法會用大寫顯示 "%e" float浮點數,以科學表示法會用小寫顯示 "%E" float浮點數,以科學表示法會用大寫顯示 "%g" double浮點數,若為科學表示法會用小寫顯示 "%#g" double浮點數,若為科學表示法會用小寫顯示,並且尾數為0時依然會顯示0 "%G" double浮點數,若為科學表示法會用大寫顯示 "%#G" double浮點數,若為科學表示法會用大寫顯示,並且尾數為0時依然會顯示0 符點數相關 "%10.3f" 輸出float符點數,預設為10個字元寬度,小數點下保留三位 "%10.3f" 輸出float符點數,預設為10個字元寬度 浮點數實測結果如下: $ printf "%#g\n" 0.0000011 1.10000e-06 $ printf "%g\n" 0.0000011 1.1e-06 $ printf "%#G\n" 0.0000011 1.10000E-06 $ printf "%G\n" 0.0000011 1.1E-06 $ printf "%10.3f\n"  0.0011      0.001 $ printf "%10.3...

C程式編譯流程

圖片
我們平常用編譯總共會經過四個階段Preprocessing, Compilation, Assembly以及Linking,gcc可以將各階段產生的結果輸出,只要依照左側的指令就能獲得各階段的檔案內容。 右下角的指令則是linking用的,其中各個.so和.o的檔案路徑是隨著Linux發行版會有不同,這裡是用Ubuntu 14.04 64bit的環境作演示。如果想查看設定可以透過gcc編譯程式碼時加上-v查看你目前電腦中的設置。 C程式編譯的四個階段

改變Ubuntu時區以及實作ISO8601標準時間格式

圖片
ISO8601是一種國際標準時間表示格式,細節請參考Wiki條目 https://zh.wikipedia.org/wiki/ISO_8601 用date可以查看電腦上的時區 $ date +%z +0800 如果要設定時區,請將環境變數TZ設定成下面網站提供的城市時區字串 https://whatbox.ca/wiki/Changing_Your_Bash_Timezone 例如: 美國紐約(-4:00)是America/New_York $ export TZ=America/New_York 而台北(+8:00)是Asia/Taipei $ export TZ=Asia/Taipei 沒有用export的話不會改date的時區 如果也可以可以找/usr/share/zoneinfo/裡面有的時區資料來用 $ find /usr/share/zoneinfo/ -name Taipei /usr/share/zoneinfo/right/Asia/Taipei /usr/share/zoneinfo/Asia/Taipei /usr/share/zoneinfo/posix/Asia/Taipei 下面是我用C/C++的strftime實作ISO 8601標準時間格式,不過Windows和Ubuntu上有些不同,Windows上用dev C++開發時發現localtime回傳的結構是沒有gmtoff欄位的,所以回傳的時間資料可以直接使用,而Ubuntu上會有gmtoff,表示時區位移資料,需要額外處理時區資訊。 #include <time.h> #include <stdio.h> int main(void) {   struct tm *local;   time_t t; #ifndef _WIN32   struct tm s_tl, s_tgm;   time_t tl, tgm; #endif   char buff[64] = {0};   char buff2[64] = {0};   t = time(NULL); // get ...

Demangle C++ function name at runtime

C++的函數名稱都會mangle 靜態Demanlge只要使用c++filt指令就能處理 動態的Demangle需要使用libstdc++的功能或是libliberty提供的函數功能 #include <iostream> #include <stdlib.h> #include <typeinfo> #include <cxxabi.h> // libstdc++ #include <libiberty/demangle.h> // libliberty // Prerequirement for Ubuntu // sudo apt-get install libiberty-dev // Please compile with -liberty // example: gcc test.cpp -liberty using namespace std; int main(int argc, char** argv) {     char* demangled_name = NULL;     int status;     int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES;     if (argc<=1) {         cerr << "Please assign a mangling C++ function name" << endl;         return -1;     }     cout << "Demangle the mangling string [" << argv[1] << "]" << endl;     // libstdc++     // https://gcc.gnu.org/onlinedocs/libstdc++/manual/...

Java與C++的函式參數傳遞比較

圖片
Java參數傳遞測試 Java的參數傳遞對於基本型態是複製,而物件型態則是類似C/C++的指標行為, 是複製物件的位址到函式中,所以在函式內assgin的新物件不影響外部變數所指的變數。 C++參數傳遞測試 而C++的參考則是會讓外部變數跟內部變數的狀態保持一致。 Java測試用程式碼 public class test {     static class MyObject {         public int iv = 0;         public String is = "initial field";         public MyObject io = this;         public MyObject() {         }         public MyObject(int primitive, String string, MyObject object) {             iv = primitive;             is = string;             io = object;         }     }     static public void setSomething(int primitive, String string, MyObject object) {         System.out.println("setSomething");         primitive = 200;     ...

C++ Print String16 in Android

簡短的寫法是丟給String8再取出來 String16 str("string16 for printing"); LOGE( "I print a string16 '%s' ", String8(str).string()); 成員函數string()會將它內部的 char8_t* b uffer位址回傳給你,LOGE就可以印出來 這個string()回傳的位址不是永久的,所以請不要保存這個位址 要注意因為是透過String8做轉換媒介,所以String8的life scope就很重要! 舉例來說, 像下面這樣的程式碼,雖然只是個印字串4次跟另一個字串1次, 但是runtime時就會看到String16轉出來跑的字串有亂碼/其他字出現。 String16 str1("string16 for printing"); char* str = String8(str).string(); LOGE( "I print a string16 '%s' first time", str); LOGE( "I print a string16 '%s' second time", str); String8* str2 = new String8("new string8 for print"); LOGE( "I print a string16 '%s' third time", str); LOGE( "I print a string16 '%s' forth time", str); LOGE( "I print a string8 '%s'", test->string()); delete str2; 這原因是String8字串的scope其實只有第二行,之後就會被解構。 那一行之後能夠運作是因為OS並不會對於是放掉的空間做清理,所以資料還殘留在記憶體上, 雖然有可能可以印的出內容,但是內容是甚麼就無...

Android的C/C++印出StackTrace

在debug Andoird上的C/C++的程式時會想印出像是Java的Stack Trace的內容 在APP裏面只需要寫一行Java就能快速的印出Stack Trace的結果 new Exception().printStackTrace(); 那在C/C++中呢? Android有提供utils這個函數庫,裡頭就有方便的CallStack可以使用 C/C++ #include <utils/CallStack.h >     CallStack cs;     cs.update();     cs.dump();  // 4.0.3     cs.log("print module name");  // 4.4.2 從logcat中看到印出來的結果會是這樣: 09-03 15:04:46.235 D/CallStack( 2583): #00 0x0x64df5730:  < _ZN17AudioVideoElement12endAnimationEv > +0x0x64df56e8 09-03 15:04:46.235 D/CallStack( 2583): #01  0x0x64d03b28:  < _ZN2js9InterpretEP9JSContextP12JSStackFramej12JSInterpMode > +0x0x64cfac88 09-03 15:04:46.235 D/CallStack( 2583): #02  0x0x64d08d40:  < _ZN2js9RunScriptEP9JSContextP8JSScriptP12JSStackFrame > +0x0x64d08c38 09-03 15:04:46.237 D/CallStack( 2583): #03  pc 000db7c8  /system/lib/libekiohplatform.so 09-03 15:04:46.237 D/CallStack( 2583...

C++同時開啟多檔案的範例

#include <iostream> #include <vector> #include <fstream> #include <string> #include <sstream> using namespace std; int main(int argc, char** argv) {     cout << argc << endl;          if (argc < 2)     {       cerr << "need parameters" << endl;       return -1;     }          ifstream in(argv[1]);     if (!in)     {       cerr << "cannot open input file" << endl;       return -1;     }     ofstream out[3];     if (argc > 4)     {       out[0].open(argv[2]);       out[1].open(argv[3]);       out[2].open(argv[4]);     }     else     {       out[0].open("col01.txt");       ou...

C++讀取命令提示字元的參數

圖片
在C/C++中讀取Command line參數 是利用Main函數的兩個參數來處理, 這兩個參數的順序與寫法是固定的, 第一個參數int型態給你的是總共有輸入幾個參數, 第二個參數char**型態給你的是參數的"字串",要注意這是C-style的字串。 NOTE: 會需要寫這個小程式的目的就是,要澄清到底是程式得到的寫錯,還是其他的問題。 下面一個可以顯示所有輸入參數的程式 #include <iostream > #include  < cstdlib > using namespace std; int main(int argc, char** argv) {     for (int i=0 ; i < argc ; ++i)         cout  < <  "["  < <  i  < <  "]"  < <  argv[i]  < <  endl;          return 0; } 實際測試這隻程式的時候會發現 在Command line 輸入 ListCommandLineArgs.exe foo 1234 會輸出 [0]ListCommandLineArgs.exe [1]foo [2]1234 程式讀取到的[0]號參數,往往都是你的程式名稱or程式路徑, 而[1]號參數之後就是我們剛剛在Command line中所輸入的。 所以實際上我們會得到的參數數目總是會多1,也就是我在Command line輸入3個參數,程式會獲得argc=4。 上面提過,因為[*]號參數都是C-style字串資料,所以我們如果要整數or浮點數資料,就需要經過轉換 C函數庫中的 atoi 和  atof 函數就可以幫忙轉換成 int 和 d...

四捨五入的問題

圖片
我們很常利用的Rounding函數會是這樣的 inline int Round(double val) {   return (int)(val+0.5); } 不過 四捨五入在負數上的運作會有點不同,下面的程式就是展示這個不同點, 就wiki上的定義  http://en.wikipedia.org/wiki/Rounding 和我們慣用的寫法在負數會有些不同, 和將負數位移成正數之後,再位移回負數的寫法, 以及+0.5之後取floor的寫法是相同的結果。 #include < iostream > #include  < cmath > #include  < cstdlib > using namespace std; int main() {   cout << "Rounding in negtive value:" << endl;   cout << (int)(-0.4 + 0.5) << endl;    cout << (int)(-0.5 + 0.5) << endl;   cout << (int)(-1.4 + 0.5) << endl;   cout << (int)(-1.5 + 0.5) << endl;   cout << "Rounding in negtive value(shift&shift back):" << endl;   cout << (int)(-0.4 + 128 + 0.5) -128 << endl;    cout << (int)(-0.5 + 128 + 0.5) -128 << endl;   cout << (int)(-1.4 + 128 + 0.5) -1...

C與C++建立2維陣列

圖片
靜態陣列 大家應該都知道如何建立,我想要整數的256*256大小的陣列就 int Array[256][ 256 ]; 雖然一般圖片較小的時候,靜態陣列就可以完成很多事情, 而且Compile 程式也不會有問題, 但是實際上程式在跑的時候,OS 會對這種靜態陣列作限制, 只要超過一定的大小,程式在跑到要配置一個大的靜態陣列,Process會直接被OS踢掉! 產生所謂的Runtime ERROR  動態陣列 要建立一個動態大小的2維陣列一般會用"指標陣列"來達成 下面會描述三種動態2維陣列的建立方法,其實概念是一樣的,只是執行效率不一樣。 我個人現在要寫都是使用第二種方法。 另外還有兩種建立2維陣列的泛用型範例,給C的是用macro寫的,給C++的是用template寫的 第一種建立方法 先建立一個 動態 指標 陣列(數量為圖片高度), 然後再為指標陣列中的每一個元素配置一個動態陣列(數量為圖片 寬度), 當我要取用動態陣列裡面的元素時,就可以用Array[h][w]來存取 而要刪除動態陣列時,則是需要先把 指標陣列中的 每一個元素所擁有的 動態陣列先刪除掉, 然後才能刪除 指標陣列本身,否則會造成Memory Leak 程式碼為     // build array          double** Array = new double*[Height];              f or (int h=0 ; h<Height ; ++h)     {       Array [h] = new double[Width];              // 初始化         for (int w=0 ; w < Width ...

Read 3D Model file (.obj) by C

平常我們使用的IO就很普通,依照我們自己訂的格式處理文字檔案內容 但是如果現在是讀取別人定義的檔案的內容呢? 有註解甚麼的... 例如3D model 的obj檔就是這種類型,它的內容會像下面這樣: # OBJ Exporter  # # object default # v  -10.2650 -20.0004 -0.1661 v  -33.1047 -15.3601 6.8245 v  -37.5988 -4.1297 6.0812 v  -50.8819 -34.2326 4.6293 v  -50.0595 -34.4188 4.7378 v  -47.7293 -34.3242 4.7756 v  -49.0474 -34.5628 4.8344 v  -48.4015 -35.0652 5.0741 # 53 vertices g default f 1 2 3  f 3 2 1  f 1 3 4  f 4 3 1  f 5 4 3  f 3 4 5  f 53 51 52  f 52 51 53  # 102 faces 那我們該怎麼讀取到C的程式中呢? #include <stdio.h > typedef struct {   float x,y,z; } fPoint;       typedef struct {   float x,y,z; } vPoint; int main() {     int i;     float f;     int data;     FILE *in, *out;         int reval;     ...