Re: [問題] 函數指標

看板C_and_CPP作者 (永遠睡不著 @@)時間9年前 (2015/03/23 09:06), 9年前編輯推噓8(8018)
留言26則, 9人參與, 最新討論串4/4 (看更多)
※ 引述《purpose (purpose)》之銘言:

03/22 21:14,
從標準的角度來看, 這些講法不盡正確. C 跟 C++ 也不盡相同
03/22 21:14

03/23 00:10,
感謝p大回覆 你的說法可以接受 但F大又說不一定正確@@?
03/23 00:10

03/23 00:12,
可以請F大賜教嗎? 或給個方向或哪些書 非常感激
03/23 00:12
其實我也不太懂,尤其是對於 C++。不過就 C 的部份我可以稍微分享一下個人的理解。 int a[3]; 就陣列來說,陣列名稱本身的型別是陣列 (如上面宣告的 a 其型別是 "長度為 3 的 int 陣列")。 在 C 標準裡面的規則是在運算時,除非做為 sizeof、取址 (&) 或 _AlignOf (C11) 的運算元,或陣列本身為 register storage,其他運算一律被轉為指向陣列第一個元素 的指標 (a 會轉為 &a[0])。而這個指標不是一個左值 (換句話說是無法被賦值 (=) 的) 依照這個規則,造成我們常理解成:在 C 裡面,一般情況下,陣列名稱就是當作指向第 一個陣列元素的指標在 "用"。甚至因為它不是一個左值,有些人會說它是個常數。 而這邊所指的一般情況甚至包含了我們最常用的陣列元素存取。 例如 a[2] 這個陣列元素存取的運算實際上會被轉為 (&a[0])[2],而 (&a[0])[2] 會用 *(&a[0] + 2) 去解釋。雖然就結果而言我們就是得到了 a 陣列的第三個元素,但是 就標準來說我們是透過指標運算去存取的。 這種種現象可能就是造成為什麼書裡面總是把陣列跟指標弄得一團亂的原因。 那函數呢 ? void f(); C 標準裡對於函數的企圖在某些層面上跟陣列有點像,但是不幸的是函數本身更複雜。 就函數來說,函數名稱本身的型別是函數 (如上面宣告的 f 其型別就是回傳 void 型態 的函數)。 在 C 標準裡面的規則是在運算時,除非做為 sizeof、取址 (&) 或 _AlignOf(C11) 的運算元,其他運算一律轉為指向函數的指標。而這個指標不是一個左值。 你看看,這不是跟陣列很像嗎? 依照這個規則,造成我們常理解成:在 C 裡面,一般情況下,函數名稱就是當作指向 函數的指標在 "用"。甚至因為它不是一個左值,有些人會說它是個常數。 但是為甚麼上面這句聽起來怪怪的,如果我們呼叫 f() 會發生甚麼事? 就標準而言就是會把 f 轉型成 &f 然後呼叫指標所指向的函數。也就是說 f() 會變成 (&f)() 然後去呼叫 &f 所指向的函數 (阿不就是 f)。 換句話說,就 C 來說,存取陣列元素 ([]) 跟呼叫函數 (()) 概念上都是透過指標。 但是指向的東西本質上卻有很大的不同。 這兩者的差別最容易理解的應該就是 sizeof,因為不論陣列或函數名稱都不會對他自動 轉型,所以我們可以用來分辨其本質的不同。 sizeof(a) 是求陣列 a 所佔據的空間大小,其結果就是整個陣列所佔據的大小,相當和 藹可親。 那 sizeof(f) 呢? C 標準跟我們說,"不可問、不可說"。對,這是個謎,而你不需要知道。 而陣列跟函數的指標運算還有一個很明顯的不同: *a 會轉成 *(&a[0]) 去存取 a 陣列第一個元素 那 *f 呢? 照剛剛的規則會變成 *(&f) 然後變成 f,接著又會套用一次同樣的規則,又變成 &f 所以就運算上 *a 跟 a 型態就已經不同,但是 *f == f 而且 *f == &f 更莫名的就是 f == **f 還有 f == *********f 至於 C++ 的話, 我只能跟你說兩者在設計的哲學上就已經不一樣. 但是我不懂 C++ 就 不好說甚麼 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.112.29.148 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1427072788.A.545.html

03/23 10:18, , 1F
再推,多看點多學點,即使佛曰不可說不可說 XD
03/23 10:18, 1F

03/23 10:22, , 2F
*_*********
03/23 10:22, 2F

03/23 11:01, , 3F
這樣a[2]轉為(&a[0])[2]後,會再轉為 (&(a[0])[0])[2]嗎
03/23 11:01, 3F

03/23 11:03, , 4F
把 &a[0] 直接解釋成陣列第一個元素的位址.
03/23 11:03, 4F

03/23 11:03, , 5F
在表達上我還沒想到最好的寫法.
03/23 11:03, 5F

03/23 12:33, , 6F
最愛 std::function 跟微笑鬍子算式 <:]{%> 了
03/23 12:33, 6F

03/23 12:50, , 7F
感謝回覆 學習了,也就是說 f *f &f type是一樣的?是嗎
03/23 12:50, 7F

03/23 13:13, , 8F
應該是說 f *f &f 行為一樣,f 有 type,而討論 *f &f 又
03/23 13:13, 8F

03/23 13:14, , 9F
是什麼 type,基本上已經沒啥意義了...我這樣說對嗎??
03/23 13:14, 9F

03/23 13:25, , 10F
看來我確實表達不好. 嚴格來說 f 跟 *f 是一樣的型態
03/23 13:25, 10F

03/23 13:26, , 11F
型別都是 "回傳 void 型態的函數". C 標準這樣的運算式名字
03/23 13:26, 11F

03/23 13:27, , 12F
叫 function designator. 這兩者在作為一般運算的運算元時
03/23 13:27, 12F

03/23 13:28, , 13F
會一律轉型為 "指向回傳 void 型態函數的指標"
03/23 13:28, 13F

03/23 13:29, , 14F
而 &f 就已經是指標了, 在做為一般運算的運算元時不會再轉型
03/23 13:29, 14F

03/23 13:29, , 15F
所以當上面用 == 運算來比較的時候會相等是因為比較時 f 跟
03/23 13:29, 15F

03/23 13:32, , 16F
*f 被轉型跟 &f 一樣了..
03/23 13:32, 16F
※ 編輯: Feis (140.112.29.148), 03/23/2015 13:44:00

03/23 15:17, , 17F
推,之前還真沒想得這麼深入....
03/23 15:17, 17F

03/23 22:31, , 18F
再次感謝。也就是說上上篇問題答案如下,有錯請指正 3Q
03/23 22:31, 18F

03/23 22:31, , 19F
1."回傳 void 型態的函數"自動轉為"指向回傳 void 型態
03/23 22:31, 19F

03/23 22:31, , 20F
函數的指標"
03/23 22:31, 20F

03/23 22:31, , 21F
2.fptr=max; 實際上為 fptr=(&max);
03/23 22:31, 21F

03/23 22:32, , 22F
3.type是一樣 都是"回傳 void 型態的函數"
03/23 22:32, 22F

03/23 22:32, , 23F
4.在fptr (*fptr)當函式呼叫時都自動轉型為(&fptr)指標
03/23 22:32, 23F

03/25 03:11, , 24F
張遼,我的頭又開始痛了
03/25 03:11, 24F

04/05 16:29, , 25F
還真沒想過size(f)是什麼鬼..@@
04/05 16:29, 25F

04/05 16:29, , 26F
不過a[2]我的理解是轉成*(a+2)這樣
04/05 16:29, 26F
文章代碼(AID): #1L3sSKL5 (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1L3sSKL5 (C_and_CPP)