作者LPH66 (f0VMRgEBA)
看板C_and_CPP
標題Re: [問題] typedef enum 的 void* 用法請益
時間Tue Aug 27 15:54:34 2013
※ 引述《remember11 (Mr.Darcy)》之銘言:
: void cb_func(eGOPLAYER_CALLBACK_TYPE type, void *data)
: {
: switch (type)
: {
: case eGOPLAYER_CBT_STATE_CHANGE:
: {
: if((eGOPLAYER_STATE)data == eGOPLAYER_STATE_PAUSE) //error
: printf("[sample]state : pause\n");
: else if ((eGOPLAYER_STATE)data == eGOPLAYER_STATE_PLAY){ //error
: printf("[sample]state : play\n");
: }
: else
: printf("[sample]state : stop\n");
: }
: break;
: default:
: break;
: }
: }
單獨回一下這篇好了
順道解說一下 Feis 提到的為什麼 callback 要使用 void * 做參數
所謂 callback 就是將某個自訂的函式送給已經寫好的程式 X 裡
程式 X 會在執行當中的某些時間點呼叫這個自訂函式
由於在程式 X 裡需要呼叫 callback 時所需要的東西是固定的
能給的東西也是固定的
因此通常一個 callback 會指定說將會送入什麼東西 期待回傳什麼東西
最常見的 callback 就是 qsort() 的第四參數
qsort 會在想要得知兩個東西的先後順序時呼叫這個 callback
然後期待一個整數做為回答
因此它所需要的 callback 就必須是 int (*)(const void *,const void *) 這種玩意
那一個 callback 有幾個狀況會指定這個函數要用 void * 做參數
這些都是 C 語言時代為了沒有 C++ 的一些高階語言特性時所用的權宜之計
其一是 qsort 的狀況 這是因為 qsort 無法得知它所排的東西是什麼
那要能夠將一個不知道是什麼的東西傳給 callback
只好傳送一個指向那東西的萬用物件指標 void * 了
(其實 qsort 壓根就完全不理解它在排什麼
只不過是把一塊資料當成一個東西在排而已)
這個問題在 C++ 靠著 template 得到解決
所以 C++ 的 sort 函式可以傳進吃任何參數的比較函式了
另一種狀況是這個 callback 在呼叫時需要使用到一些不屬於程式 X 的東西
有的地方這種東西會被叫做 userdata 「使用者資料」
因為不屬於程式 X 所以無法得知那是什麼 只好用萬用物件指標 void * 表示
在這種狀況裡通常呼叫程式 X 的地方會有一個 void * 參數可以傳東西進去
這個問題在 C++ 則是藉著 functor 的使用獲得解決
一個 functor 是個物件 但它能夠用類似函式的語法呼叫
(實質上是呼叫該物件的 operator () 成員函式)
那既然是個物件 夾帶點東西闖關(?)也就很簡單了
原 PO 的程式則是又一個狀況
在這種狀況裡程式 X 是會在不同的地方呼叫同一個 callback
程式 X 的需求靠著第一個參數解決 而該需求的參數則以第二個參數傳遞
某種程度上還滿像是 Win32 的 message 架構的
這樣一來 由於第二個參數不一定會是哪個固定型
所以就必須使用萬用物件指標 void * 表示了
這裡的 void * 意義可能有兩種 這是關於 primitive type 如何使用這個參數
其一是 Win32 message 使用的方式
Win32 的 message 架構也是有著跟這裡的 void * 相像的兩個參數
叫做 LPARAM 跟 WPARAM 前者是有號整數參數 後者是無號整數參數
由於這些參數也常傳遞指標所以它們的型態是可以將指標轉過來的整數
分別叫 LONG_PTR 跟 ULONG_PTR 這樣只傳整數時也不會有太多的負擔
(可以把它理解成 intptr_t 跟 uintptr_t 即可)
當參數是整數時直接把這個參數 cast 成整數就行了
另一種寫法是不論參數是什麼都傳遞指向它的指標進去
即使參數只單單是個整數或 enum 也是
這種狀況下要做的則是要將參數 cast 成適當的指標再提值
不過原 PO 這支程式似乎卡在這兩種寫法的中間
它似乎想要用類似 Win32 message 的參數做法
但又在參數列上放 void * 這是另一種寫法才會用的
這樣一來原 PO 你必須要去看你這個 player_open 的說明
看他裡面說 callback 被呼叫時參數是怎麼傳進去的
是屬於這兩種寫法的哪一種
如果是後者那就照我上面寫的 先轉成 eGOPLAYER_STATE * 再提值
如果是前者...那可能需要中間先轉成 int 再轉成 eGOPLAYER_STATE 才行了
--
い
ああオレたちには見えてるモノがあるbデ きっと誰にも奪われないモノがあるはずさ
け
開口一番一虚一実跳梁跋扈形影相弔yュL羊頭狗肉東奔西走国士無双南柯之夢 歪も
ぶ
意味がないと思えるコトがある ラPきっとでも意図はそこに必ずある んの
く
依依恋恋空前絶後疾風怒濤有無相生 ラH急転直下物情騷然愚者一得相思相愛 だが
ろ
無意味じゃない ラ6あの意図が 恋た
で
有為転変死生有命蒼天已死黄天當立 !!6五里霧中解散宣言千錯万綜則天去私 のり
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.30.32
推 remember11:謝謝大大詳解,感激。不過我稍早之前亂try,有試出來了 08/27 17:26
→ remember11:我是把我註解error那兩行改成 08/27 17:26
→ remember11:if(data == (void*)eGOPLAYER_STATE_PAUSE) 08/27 17:27
→ remember11:我是亂試出來的,我不熟C++,指標更是新手 08/27 17:28
→ remember11:所以為什麼這樣解可以,會不會有危險,我也不清楚@@ 08/27 17:28