首頁>技術>

以下是我在實際專案開發中總結的程式裡面常見的C用法和技巧。

1.printf輸出資料格式:

下面一段程式碼:

#include <stdio.h>

int main()

{

int i = 0x200, j = 0x2;

printf("%2x\\n", i);

printf("%02x\\n", j);

}

在Visual Studio 驗證,執行結果:200 02

x 表示以十六進位制的輸出格式,%02x 表示輸出佔兩個字元的位置,不足兩位,前面補0輸出;超出兩位限定值,按原值全部輸出。

2. 陣列賦值

static const char *table[]

{

[a] = "H",

[b] = "E",

[c] = "L",

[d] = "L",

[e] = "O",

};

Linux原始碼和一些第三方庫檔案中有類似用法,對陣列賦值操作時,可單獨對第幾個元素進行賦值。比如[1]={...};就是對第一個元素進行賦值。如下:

int num[5] = {1,2,0,0,3};也可以寫成

int num[5] = {[0] = 1,[1] = 2,[4] = 3};

也可以給陣列下一個連續的元素賦值,比如:

int num[5] = {[1] = a,b,[4] = c};等價於

int num[5] = {0,a,b,0,c,0};

3. 資料高低位

a對於一個16位的二進位制數要在記憶體中分配,

DL = v % 256; //低八位

DH= v / 256; //高八位

"/"是除法後取整數,"%"是除後取餘數。

b.分別取一個16位的二進位制數的高低位:

#define val16_get_high18(val) ((val>>8)&0xFF)//取高8位

#define val16_get_low18(val) (val&0xFF)//取低8位

把一個32位的二進位制數轉化成16位二進位制數儲存:

#define val32_get_high16(val) ((val>>16)&0xFFFF)

#define val32_get_low16(val) (val&0xFFFF)

把一個32位的二進位制數轉化成8位二進位制數儲存:

#define val32_get_high8(val) ((val>>24)&0xFF)

#define val32_get_mid8(val) ((val>>16)&0xFF)

#define val32_get_midd8(val) ((val>>8)&0xFF)

#define val32_get_low8(val) (val&0xFF)

4. Gcc優化及去除優化

在很多程式碼中遇到#pragma GCC optimize ("O3"),這是對程式碼進行優化,減小程式碼大小及所佔棧空間大小,但是優化後注意位元組對齊,不然程式會出現問題。Gcc優化級別分為O0,O1,O2,O3,Os等,O0為不優化。

對部分程式碼去優化及優化操作:

#pragma GCC push_options#pragma GCC optimize ("O0").......#pragma GCC pop_options

還有通過volatile關鍵字也可以禁止Gcc優化。

5.ceil/floor函式

ceil(val)向上取整函式,返回大於或者等於指定表示式val的最小整數;

floor(val)向下取整函式,返回引數不大於val的最大整數。比如:

ceil(3.1415)=4;

floor(3.1415)=3;

6. do while(0)語句

do while(condition)表示迴圈語句,但是也用在了巨集定義中,比如這種程式碼形式:

#define hal do {\\

/*code*/

}while(0)

這種形式常見的用於巨集定義,在這裡,是保證迴圈體語句的一次執行,為了巨集展開的時候不會出錯,如直接放在花括號會出錯的。比如:

#define hal {code1;code2} //{...}可以是定義多個變數或者函式

作用:

(1)替代{},實現區域性作用域.在一些C的實現裡也可以用;(2)避免使用goto,用break語句跳出。類似於while(true){ ... break;}

(3)補充空巨集定義,避免一些warning

#define hal do {}while(0)

7. 位元組對齊

常見#pragma pack(n) 和 __attribute__((aligned)) 這兩種對齊方式。在預設預設情況下,編譯器一般按自然對界條件給變數和資料單元分配記憶體空間,要改變預設預設位元組對齊方式就通過這兩種方式。先介紹#pragma pack(n)用法:

使用#pragma pack(n),指定變數按照n個位元組對齊;使用#pragma pack(),取消自定義位元組對齊方式。

如預設情況下(實驗基於KEIL,不同的系統硬體環境,不同的編譯器結果可能不一樣):

typedef struct {

int a;

char b;

short c;

}A;

由於編譯器預設對結構體資料成員進行對齊,有插入的空位元組,就是佔8個位元組的空間,如果用我們指定的位元組對齊方式,如:

#pragma pack (1)

typedef struct {

int a;

char b;

short c;

}A;

這樣sizeof(A)執行結果就是7個位元組。下面再來介紹__attribute__((aligned))的用法:

__attribute__((aligned)) 以位元組為單位按照變數或者結構體的最小長度進行對齊。

__attribute((aligned (n))) 指定變數或者結構體資料成員對齊在n位元組自然邊界上。若資料成員的長度大於n,則按照最大資料成員的長度來對齊。

__attribute__ ((packed)),取消指定變數或者結構體資料成員在編譯過程中的優化對齊,按照實際佔用位元組數進行對齊。

如:

typedef struct {

int a;

char b;

short c;

}__attribute__((aligned)) A;

sizeof(A)所佔是8個位元組;如果限定位元組對齊:

typedef struct {

int a;

char b;

short c;

}__attribute__((aligned(16))) A;

sizeof(A)所佔是10個位元組。比如在32位系統一般會按照4位元組協議來進行位元組對齊。這樣合理使用位元組對齊可以提高CPU訪問速度和節省記憶體空間。如果32位系統中按照>4或著<4位元組來對齊(2^n來對齊),CPU一般會讀取多次,這樣降低了訪問效率。參考來自KEIL help文件:

  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Linux系統核心首次加入鎖定功能