bloggerads

2014年10月25日 星期六

C/C++一些經驗談

一些雜談,提供個人Coding 的經驗

1. 無窮迴圈的例子: 沒有注意宣告的變數範圍上限或邏輯錯誤而溢位產生無窮迴圈
  1. for (unsigned char x=0; x<=0xff; x++) ;
  2. for (unsigned char x=0xff; x>=0; x--) ;
2. 宣告雙指標的時機
用指標來管理記憶體,而雙指標(指標的指標)就是用指標管理指標
實務上在函式間傳遞指標的位址時, 就必需要傳遞指標的指標。舉個記憶體管理的例子,假如我有一串link list如下p1~p6,就可以透過雙指標pp start/pp tail指定鏈結串鏈其中一段的起始節點位址(&p2)和尾部節點位址的(&p5), 而PP start/ PP tail就是雙指標的型態

3. Big Endian Vs Little Endian
假如我有一串binary,他是一連串的DWORD組成,試問該如何去解釋這個binary內容呢。答案是在不同機器上就有不同的解讀方法。

a. Little Endian : 低位元放低位址 (常見於x86系統)

+  #define VAL_TO_ARRAY_LITTLE_ENDIAN( array, val ) \
+  do { \
+      (array)[1] = (val) >> 8; \
+      (array)[0] = (val) & 0xFF; \
+  } while(0) 

b. Big Endian : 高位元放低位址 (有些spec欄位會定義成這種)


4. 宣告64位元變數
比較新的GCC版本都有支援宣告64位元變數,一般在Linux kernel code看到常數後面跟著ull,就代表他的定義是64位元變數的常數。我自己使用上不加ull也不會產生問題(Watcom/gcc),但是在輸出螢幕時必須使用%llX,(只有%X顯示不出bit 63:32),以下提供各長度型態宣告方法

+ typedef unsigned long long QWORD, u64;
+ typedef unsigned int DWORD, u32;
+ typedef unsigned short WORD, u16;
+ typedef unsigned char BYTE, u8;


5. 巨集"敘述"化
巨集 A用 do{} while(0)  或 {} 將程式寫成一個敘述,在呼叫時不會產生錯誤。同樣的程式寫成巨集 B,這樣呼叫方式則會產生錯誤

+  // 巨集A
+ #define TMACRO(pstr) {//do{\
+  printf("log:\n");\
+  printf(pstr);\
+  }//while(0)

+  //  巨集B    
+  #define TMACRO(pstr)\
+  printf("log:\n");\
+  printf(pstr)

+  // Call TMACRO
+  if (x>=y)
+      TMACRO("x>=y\n");
+  else
+      TMACRO("x<y\n");


6. 前置處理器
廣泛使用在韌體版本控制(不同版本通常硬體設定都會不同)

+  //#define XX
+  #if !defined(XX) 
+      printf("not define XX\n");
+  #elif defined(XX)  &&  (ZZ > 1)
+      printf("define XX and ZZ > 1 \n");
+  #else
+      printf("define XX and ZZ == 0\n");
+  #endif
+  
+  #ifdef XX
+      printf("define XX\n");
+  #endif
+  
+  #ifndef XX
+      printf("not define XX\n");
+  #endif


7. 在程式中顯示build code time 
提供時間做參考,以免同一版程式被更改了但是卻沒進版

+  printf( "%s %s", __DATE__, __TIME__); //The __DATE__ and __TIME__ macros are predefined by the compiler

加額外的information, 如哪一個檔案/函式/第幾行出錯

+   printf( "File        : %s\n", __FILE__ );
+   printf( "Function : %s\n", __FUNCTION__ );
+   printf( "Line       : %d\n", __LINE__ );

8. 盡量不要用goto, exit()這類的語法,因為這類的語法屬於直接跳躍指令造成程式可讀性變差


9. strlen 和 sizeof 的誤用
strlen()回傳的是字串長度(所以不含結束字元'\0')而sizeof()是回傳此變數型態宣告的大小

+  char p[10]="123";
+  printf("  %d\n", sizeof(p));  // print 10

+  printf("  %d\n", strlen(p));  // print 3

7. 善用可變數目參數,在這例子是把printf, fprintf用define統合寫在一起處理 

+  #define HybridPrintf(fp, ...) {\
+  printf( ##__VA_ARGS__);\
+  fprintf(fp, ##__VA_ARGS__);\
+  }

8. array的初始化

+   char buffer[] = { 'a', 'b', 'c' };

可把初始化那個 index 寫成如下:

+   char buffer[] = { [0] = 'a', [1] = 'b', [2] = 'c' };

9. 指標的宣告

下行是錯誤的

+  int* p1, p2; // p2 的 type 是 int

要改成

+  int *p1,  *p2; // 但是不好

或改成

+  typedef int * pInt;
+  pInt p1, p2;

(待續)


1 則留言: