標籤:C語言 C語言關鍵字
001 關鍵字
- C語言一共32個關鍵字1. 聲明和定義
- 在開始認識關鍵字前,必須要明白什麼是聲明,什麼事定義:
- 定義:(編譯器)建立一個對象,為這個對象分配一段記憶體並給他取上一個名字。在一個範圍內,一個變數或者對象只能定義一次,並且定以後為它分配的記憶體不可變;
- 聲明:1、告訴編譯器這個名字已經和一片記憶體匹配上了,並且這個記憶體是在其他地方定義的,聲明可以多次;2、告訴編譯器,這個名字已經佔用,不能再用來定義其他變數或者對象了。
- 備忘:定義建立了對象,並為它分配了記憶體,聲明沒有分配記憶體
2. 關鍵字2.1. auto(最寬宏大量的關鍵字)
- 在預設情況下,編譯器預設所有變數都是auto的,所以我們可以當它不存在。
2.2. register(最快的關鍵字)
- 請求編譯器,儘可能的把使用register定義的變數發到CPU的寄存器中,不保證一定放。(CPU的寄存器有限)
- 注意:register變數長度應該小於等於int,並且不能使用&(register變數不存放在記憶體中)
2.3. static (最名不符實的關鍵字)
- 修飾變數
- 修飾全域變數,從定義開始到檔案結束可用,其他檔案即使使用extern 也不能使用
- 修飾局部變數,只能在函數體裡面使用
- 由於被static修飾的變數都是存放在記憶體的靜態區,所以即使函數運行結束,這個變數也不會被銷毀,函數下次使用時任然能用到這個值。
- 修飾函數
- 函數使用static修飾表示範圍僅限於本檔案,又稱內建函式
2.4. short、int、long、char、float、double(基礎資料型別 (Elementary Data Type))
- 變數的命名規則
- min length && max information
- 望而知意,便於記憶
- 由多個單片語成是,要麼用底線隔開,要麼每個單字首大寫
- 盡量避免出現數字編號,除非邏輯上需要
- 所有宏定義、枚舉常數、唯讀變數全部用大寫字母命名,用底線分割單詞
- 迴圈變數 n 、m、i、j、k;char c; int a[]; int *p 。
2.5. sizeof (最冤枉的關鍵字)
- sizeof 是 32 個關鍵字中的一個,而不是一個函數。
- sizeof(int) * p 表示什麼意思呢?
2.6. signed unsigned 關鍵字
#include <stdio.h>#include <string.h>int main(){ signed char a[1000]; int i = 0; for (i = 0; i < 1000; i++) { a[i] = -1 - i; } printf("%d\n", strlen(a)); return 0;}
當 i = 128 的時候,a[128] = -1 - 128 = -129 ,signed char 的取值範圍是 -128~127,所以超出了範圍,-129 源碼: 1 1000 0001 ,補碼:1 0111 1111 ,低 8 位 0111 1111 ,即 127。
當 i = 255 的時候,a[255] = -1 - 255 = -256 , -256 的原碼 11 0000 0000 補碼:11 0000 0000 ,低 8 位全為 0, strlen 遇到 ‘\0‘ 就結束,所以上述代碼輸出 255。
所以,char 類型如果直接使用就用來表示字元,如果加了 signed 和 unsigned 限定符的話就用來表示數字。
2.7. if else 組合
bool b = FALSE;if(b) printf("TRUE");if(!b) printf("FALSE");
上面這種寫法是值得推薦的,其他方式會有問題。
- float 變數與“零值”比較
if(test > -EPSINON) || (test < EPSINON); // EPSINON 為定義好的精度
- 指標變數與“零值”比較
if(NULL == p)if(NULL != p)
- 先處理正常情況後處理異常情況或者說先處理機率大的,再處理機率小的
- 賦值運算不能用在產生 bool 值得運算式上
if((x = y) != 0 )printf("------");
這樣寫是錯誤的,應該這樣寫
x = y;if(x != 0)printf("-----");
2.8. switch case 組合
當嵌套比較少量的分支的時候可以使用 if else 組合,但是當嵌套的分支多的時候就要使用 switch case 組合了,但是也不要刻意去創造一個 switch 變數。
- 每個case 的結尾不要忘了 break; 除非你有意讓多個分支重合。
- 最後必須使用 default 分支,也需要 break; 。
- 在 switch case 組合中禁止使用 return 語句。
- switch 運算式不應該是有效 bool 值,例如下面的運算式是不允許的。
switch (x == 0){......}
- case 後面的值只能是×××或者字元型的常量或者常量運算式。
- case 語句的拍立順序
- 按照字母順序排列
- 把正常情況放在前面,把異常情況放在後面,並做好注釋,哪裡是開始,哪裡是結束。
- 把常執行的情況放在前面,不常執行的情況放在後面。
- 沒種情況的相關代碼要盡量簡潔,必要時可以使用函數。
2.9. do while for 關鍵字
2.10. goto 關鍵字
goto 關鍵字可以在代碼中靈活的跳轉,存在很大的爭議,有的建議慎用 goto ,有的建議不要用。我覺得用得好還是可以用。
int *p = NULL;...goto error;...error: return -1;
2.11. void 關鍵字
void *p = NULL;int *p_int = NULL;p = p_int; //不會報錯,是正確的p_int = p; //報錯,是錯誤的
- void 修飾函數傳回值和函數參數
- void 不能代表一個真實的變數,例如下面的代碼是錯的
void a;fun(void a);
2.12. return 關鍵字
2.13. const 關鍵字
- const 修飾的唯讀變數必須在定義的同事初始化(首先 const 修飾的變數,其次是唯讀,兩層含義)
- 想一想 switch case 中 case 語句後面就可以是 const 修飾的唯讀變數嗎?
先忽略類型,看 const 離誰近就修飾誰
const int *p; // const *p ,修飾 *p , p 可以改變, p 指向的內容不可變int const *p; // const *p ,同上int * const p; // * const p ,修飾 p,p 不可以改變,p 指向的內容可以改變const int * const p; // const * const p ,第一個 const 修飾 *p,第二個 const 修飾 p,所以 p 和 p 指向的內容都不能改變
- 修飾函數的參數,當不希望函數的參數在函數體中被改變的時候可以使用 const 修飾函數的參數。
- 修飾函數的傳回值(const int fun(void))。
- 在另一個檔案引用 const 變數時使用 extern const int i; 聲明即可,而不是定義。
2.14. volatile 最易變的關鍵字
- volatile 關鍵字和 const 一樣,是一種類型修飾符。它修飾的變數表示可以被某些編譯器未知的因素更改,比如作業系統,硬體或其他線程。遇到這個關鍵字修飾的變數,編譯器就不對它做最佳化,每次需要訪問的時候都重新去記憶體中讀取。
在這裡 volatile 只是告訴編譯器 a 的值可能會被改變,需要訪問時每次都要重新到記憶體中去取。
2.15. extern 最會戴帽子的關鍵字
- 修飾函數和變數,表示函數和變數不是在本檔案定義的,在本檔案只是使用 extern 聲明。
2.16. struct 關鍵字
空結構體佔多大記憶體?大多數編譯器是 1,gcc 是 0。所以不要太相信書本上的東西,一定要自己親自驗證。
- 柔性數組
- 不要驚訝,C語言中確實有柔性數組這個說法的。
- C99 中,結構體最後一個成員允許是未知大小的數組,這就是柔性數組。但是柔性數群組成員前必須至少有一個其他成員。sizeof 計算的大小不包含柔性數組所佔的空間。為包含柔性數組的結構體分配記憶體要使用 malloc ,並且分配的記憶體應該大於 sizeof計算的值。
typedef struct st_type{ int i; a[0];}type_a;//有些編譯器會報錯,可以改成typedef struct st_type{ int i; int a[];}type_a;
//可以使用下面的代碼為柔性數組分配記憶體,但是分配好之後使用 sizeof 計算結構體的大小依然是不包含柔性數組所佔的記憶體的。type_a *p = (type_a *)malloc(sizeof(type_a) + 100 * sizeof(int));//記得用完之後要 freefree(p);
2.17. union 關鍵字
- union 中所有資料成員共用一塊記憶體,同一時間只能儲存其中一個資料成員。union 的大小是最大成員所佔記憶體的大小。2.17.1. 大小端對 union 類型資料的影響
union { int i; char ch;}c;c.i = 1;//這時候 ch 只需要一個位元組儲存,在低地址,如果 ch 的值等於 1, 說明 i 的值得低位元組 1 儲存在低地址,是小端模式。Ubuntu、Windows 等 x86 架構都是小端模式。
int main(){ int a[5] = { 1, 2, 3, 4, 5 }; int *p1 = (int *)(&a + 1); int *p2 = (int *)((int)a + 1); printf("%x %x\n", p1[-1], *p2); return 0;}// 5 2000000 小端模式 大端模式 5 2
2.18. enum 關鍵字
enum enum_type_name{ ENUM_CONST_1, ENUM_CONST_2, ENUM_CONST_3, ... ENUM_CONST_n} enum_variable_name;
- enum_type_name 是自訂的枚舉類型,而 enum_variable_name 是 enum_type_name 類型的一個變數。
- sizeof(enum_variable_name) 的值是多少呢? 想想枚舉成員的類型就會知道是 4 了, 空枚舉類型的大小也是 4。
2.19. typedef 關鍵字,最偉大的縫紉師
- typedef 是給已經存在的資料類型取一個別名,而不是重新定義新的資料類型。
typedef struct student{ int age; char name;} stu_1, *stu_2;const stu_2 student_1; // 其實是 const (struct student *)student_1; 所以 修飾的是 student_1 本身,而不是指向的內容stu_2 const student_2; // 其實是 (struct student *)const student_2; 所以 修飾的也是 student_2 這個指標本身,而不是指向的內容
#defien INT32 inttypedef int INT32_tunsigned INT32 i = 10; //沒問題,只是替換unsigned INT32_t j = 10; //錯誤,不支援#defien PCHAR char*typedef char* pcharPCHAR ch1, ch2; //ch1 是 char * 類型,ch2 卻是 char 類型pchar ch2, ch4; //ch3, ch4 都是 char * 類型
3. 總結
不複習不知道,一複習嚇一跳,原來 C語言 關鍵字還有這麼多知識點,以前也沒怎麼注意,當然不止這些,我只是記錄了我認為比較重要而且容易搞混淆的。
如果你覺得我的讀書筆記對你有用,可以關注公眾號 kalier 哦,最新的文章和讀書筆記都將在這裡首發。
讀書筆記-C語言關鍵字