指標篇 - 筆記
===
# 複雜宣告
常會看到一些很複雜的宣告
要理解這些宣告可以簡單的用以下規則來判斷
| 規則 | 補充 |
| -------- | ------------------------|
| 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`