以下是我在實際專案開發中總結的程式裡面常見的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文件: