指標篇 - 筆記 === # 複雜宣告 常會看到一些很複雜的宣告 要理解這些宣告可以簡單的用以下規則來判斷 | 規則 | 補充 | | -------- | ------------------------| | 1.從內往外讀 | 先找變數名稱 | | 2.先往右看 | 是否為 Function? Array? | | 3.再往左看 | 是否為 pointer? | | 4.先處理括號內的 | Type values | | 5.最後的 Type 是什麼 | int? long? | | | 念法用以下替換 | | -------- | ------------------------------- | | Function | Function returning | | Array | Array of X elements , which are | | * | Pointer to | | Type | Type values | 直接看規則可能看不懂,看下面例子說明 ## 舉例 ```c= int *var[5]; ^ ^ ^ ^ 4 3 1 2 ``` 1. 先找變數名稱 : `var is declared as` 2. 先往右看是一個大小為 5 的 Array : `Array of 10 elements, which are` 3. 再往左看是 * : `Pointer to` 4. 最後是 Type : `int values` 合併就是 : `var is declared as Array of 10 elements, which are Pointer to int values` 中文就是 : `var 被宣告為一個 10 大小的陣列,陣列裡的元素為指向 int 的指標` ```c= int (*var)[5]; ^ ^ ^ ^ 4 2 1 3 ``` 1. `var is declared as` 2. 因為 var 被括號包住,所以先看括號裡面的 : `Pointer to` 3. 往右看是一個大小為 5 的 Array : `Array of 10 elements, which are` 4. 最後是 Type : `int values` 合併就是 : `var is declared as Pointer to Array of 10 elements, which are int values` 中文就是 : `var 被宣告為一個指標,指向大小為 10 的陣列,陣列裡的元素的型態是 int` ```c= long *var( long, long ); ^ ^ ^ ^ 4 3 1 2 ``` 1. `var is declared as` 2. 往右看是一個 Function : `Function returning` 3. 再往左看是 * : `Pointer to` 4. 最後是 Type : `long values` 合併就是 : `var is declared as Function returning Pointer to long values` 中文就是 : `var 被宣告為一個 Function,此 Function 會回傳指向 long 的指標` ```c= long (*var)( long, long ); ^ ^ ^ ^ 4 2 1 3 ``` 1. `var is declared as` 2. 因為 var 被括號包住,所以先看括號裡面的 : `Pointer to` 3. 往右看是一個 Function : `Function returning` 4. 最後是 Type : `long values` 合併就是 : `var is declared as Pointer to Function returning long values` 中文就是 : `var 被宣告為一個指向 Function 的 pointer,此 Function 會回傳 long` ```c= struct both { int a; char b; } ( *var[5] )( struct both, struct both ); /* 可以先把前面一大堆看成一種 Type 就號,簡化如下 */ both ( *var[5] )( struct both, struct both ); ^ ^ ^ ^ 3 1 2 4 ``` 1. `var is declared as` 2. 往右看是一個大小為 5 的 Array : `Array of 10 elements, which are` 3. 再往左看是 * : `Pointer to` 4. 往右看是一個 Function : `Function returning` 5. 最後是 Type : `both values` 合併就是 : `var is declared as Array of 10 elements, which are Pointer to Function returning both values` 中文就是 : `var 被宣告為一個 10 大小的陣列,陣列裡的元素為指向 Function 的指標,此 Function 會回傳both 型態` # 呼叫 Function 上面是說明如何理解複雜的宣告,這裡說明如何呼叫 Function,首先有個宣告如下 ```c= void (*func_ptr)(); ``` 根據上述觀念就是 : `func_ptr is declared as Pointer to Function returning void values` `func_ptr` 就是一個指向 Function 的指標而已 ```c= func_ptr array[3]; ``` 這樣表示有個大小為 3 的陣列,陣列裡存的元素都是指向 function 的指標 所以你可以把實作好的 function assign 給 array ```c= void FuncA(){ printf("Hi! A"); } void FuncB(){ printf("Hi! B"); } void FuncC(){ printf("Hi! C"); } array[0]= &FuncA; array[1]= &FuncB; array[2]= &FuncC; /* 用以下方法呼叫 fcuntion */ (* (array[0]) )(); (* (array[1]) )(); (* (array[2]) )(); /* 等同於 */ FuncA(); FuncB(); FuncC(); ``` 所以這裡有一個重點是,當你要使用 Function Pointer 來呼叫 function 時 要使用 : ` (* (Function Pointer) )(); ` # C Traps and Pitfalls 的案例 ```c= (*(void(*)())0)(); ``` 首先可以看出這是呼叫 fcuntion ```c= (* (void(*)())0 )(); (void(*)())0 = ( void (*var)() )0 = (Function Pointer)0 ``` 再根據上述方法改寫成 `var is declared as Pointer to Function returning void` :::info 結論如下 :mega: 0 是一個位址,我們可以知道 0 這個位址存放一個 Function 此 Function 沒有參數也沒有回傳值,最後呼叫此 Function ::: ```c= void **(*d) (int &, char **(*)(char *, char **)); ``` 這題也可以簡單看成下面宣告 ```c= void **(*d) ( A, B); ``` 那 d 再根據之前的方法來解釋為 `d is declared as Pointer to Function returning Pointer to Pointer to void` # 參考資料 [Microsoft : 如何了解複雜的宣告](https://docs.microsoft.com/en-us/cpp/c-language/interpreting-more-complex-declarators?view=msvc-160) ###### tags `C`