精華區beta C_and_CPP 關於我們 聯絡資訊
※ 引述《gocpp (cpp)》之銘言: : 一般有幾種習慣: : T* p; // 向型別 T 看齊 : T *p; // 向變量 p 看齊 : T * p; // 不偏不倚 這的確是見仁見智,style 一致就好。 像是 int* p; 和 int *p; 第一種是強調 type,也就是說 p 的 type 是 int*, 第二種是強調 syntax, * 和 p 都是 "declarator" 的一部份。 int 則是 "type specifier" 的一部份,C 和 C++ 的 syntax 分類的定義都如此。 : 似乎用第一種寫法的人比較多,很多 C++ 大師都是如此。 : 我個人是比較習慣第二種寫法,原因是當有兩個以上的指標: : T *p1, *p2; : 第二種寫法顯然比較合理,這時如果這樣寫: : T* p1, p2; : 那 p2 就不是指標而是物件了。 以下連結是真正的 C++ 大師(也就是 C++ 發明者本人啦)的說明, 為什麼他個人採用 T* p; 的寫法,他也提到了相反立場者所持包括 上面引文的理由。 http://www.research.att.com/~bs/bs_faq2.html#whitespace : 個人認為第二種寫法的最大好處,就是便於理解: 我個人是 T* p; 派的,下面這些例子,採用 T* p; 的寫法, 對我來說,反而能看得更清楚。 : 例如(一律由右往左看): : T *p; // p 是一個指標,指向一個型別 T 的物件 : T &r; // r 是一個 reference,參用一個型別 T 的物件 : 又(同樣一律由右往左看): : T *f(); // f 回傳一個指標,指向型別 T 的物件 : T &g(); // g 回傳一個 reference,參用一型別 T 的物件 : 又(同樣一律由右往左看): : T *const p; // p 是一個 const 指標,指向型別 T 的物件 : T const *p; // p 是一個指標,指向型別 T 的 const 物件 : T const *const p; // p 是一個 const 指標,指向型別 T 的 const 物件 : const T *const p; // 同上(只要保持由右往左讀的習慣,就不會昏頭弄錯) : 甚至(還是由右往左看): : T *const f(); // f 回傳一個 const 指標,指向型別 T 的物件 : T const &g(); // g 回傳一個 reference,參用一個型別 T 的 const 物件 : T *&h(); // h 回傳一個 reference to pointer,參用一指標,該指標指向 : // 一型別 T 的物件 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.130.208.168 > -------------------------------------------------------------------------- < 作者: renderer (rendering) 看板: C_and_CPP 標題: Re: [討論] 關於指標記號 * 的位置 時間: Fri Aug 19 22:21:05 2005 ※ 引述《gocpp (cpp)》之銘言: : 一般有幾種習慣: : T* p; // 向型別 T 看齊 : T *p; // 向變量 p 看齊 : T * p; // 不偏不倚 個人比較習慣 T* p; 理由是在「視覺上」對於「型別的識別」會比較清楚而快速 而且比較不會誤看 : 似乎用第一種寫法的人比較多,很多 C++ 大師都是如此。 : 我個人是比較習慣第二種寫法,原因是當有兩個以上的指標: : T *p1, *p2; : 第二種寫法顯然比較合理,這時如果這樣寫: : T* p1, p2; : 那 p2 就不是指標而是物件了。 我會儘量避免合在一起寫 而改成: T* p1; T* p2; : 個人認為第二種寫法的最大好處,就是便於理解: : 例如(一律由右往左看): : T *p; // p 是一個指標,指向一個型別 T 的物件 : T &r; // r 是一個 reference,參用一個型別 T 的物件 : 又(同樣一律由右往左看): : T *f(); // f 回傳一個指標,指向型別 T 的物件 : T &g(); // g 回傳一個 reference,參用一型別 T 的物件 : 又(同樣一律由右往左看): : T *const p; // p 是一個 const 指標,指向型別 T 的物件 : T const *p; // p 是一個指標,指向型別 T 的 const 物件 : T const *const p; // p 是一個 const 指標,指向型別 T 的 const 物件 : const T *const p; // 同上(只要保持由右往左讀的習慣,就不會昏頭弄錯) : 甚至(還是由右往左看): : T *const f(); // f 回傳一個 const 指標,指向型別 T 的物件 : T const &g(); // g 回傳一個 reference,參用一個型別 T 的 const 物件 : T *&h(); // h 回傳一個 reference to pointer,參用一指標,該指標指向 : // 一型別 T 的物件 由左往右讀也可以 尤其是以中文思考的時候 int p; int p int* p; int 的指標 p int& p; int 的參考 p int const * p; int constant 的指標 p ( constant 解讀成名詞:常數 ) int 常數的指標 p int* const p; int 指標的常數 p int const * const p; ((int 常數) 指標) 的常數 p int* p[5]; ==> int*[5] p; // 以 p 為軸將 [5] 搬到左邊 (int 指標) 的陣列 p 共5個 int* p[5][3]; ==> int*[3][5] p; ((int 指標) 的陣列) 的陣列 p 共3個 共5個 int (* p)[5]; ==> int[5]* p; // 以 (* p) 為軸 int 陣列的指標 p 習慣由右往左讀的同學別被我誤了 C/C++ 本身就是一種語言 能直接解讀程式本身是最好的 不必翻成英文或中文解讀 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.228.217.108 ※ 編輯: renderer 來自: 61.228.217.108 (08/19 22:26) ※ 編輯: renderer 來自: 61.228.217.108 (08/19 22:30)
drkkimo:我也是慣用Type* 變數名稱 218.164.24.136 08/19
clifflu:我喜歡 T * p; 因為 * 不是 CDATA, 看起來怪怪的140.112.212.129 08/19
khoguan:呵呵 :-) renderer大大有在擔任教職嗎?220.130.208.168 08/20
renderer:沒有耶 程度不夠呀 61.228.217.108 08/20
renderer:像 k大對 C++有很清楚的瞭解 就滿適合教 C++ 的 61.228.217.108 08/20
khoguan:r大 才有循循善誘、誨人不倦的教師風範呀 :-)220.130.208.168 08/20
> -------------------------------------------------------------------------- < 作者: UNARYvvv (有趣生活) 看板: C_and_CPP 標題: Re: [討論] 關於指標記號 * 的位置 時間: Fri Aug 19 23:12:24 2005 ※ 引述《gocpp (cpp)》之銘言: : 一般有幾種習慣: : T* p; // 向型別 T 看齊 : T *p; // 向變量 p 看齊 : T * p; // 不偏不倚 我習慣用 T *p; 而對型別的辨認,因為我的解讀是看到 *p 先知道 p 是個指標 然後再往回找它指向什麼 而且有時候不只一個指標變數的時候 我可能也會用 T *p1, *p2; 寫在同個 statement 而不是兩個 用到現在也就是都這樣寫了 也由於習慣,所以在閱讀上也並未覺得麻煩 以前是看 The C Programming Language & C++ Primer 這兩本書 分別作為學習 C/C++ 的入門書 裡面的 code 也是用 char *p; 這樣 C++ Primer 有特別提到要注意這點 (忘記 K&R 有沒有) 然後我認同了(偏好) T *p; 這種 * 號靠著變數名的寫法 到現在習慣也就是這樣了。好像跟前面幾位都不同XD 題外話 講到這個就想起以前修 OOP (其實內容是在教 C++ 語言) 的課時 某次上機考,老師出一個 binary tree 的題目 代表 node 的 structure 如下: struct TreeNode { TreeNode* left,right; } 然後一些對宣告指標相關語法不太熟的同學 每次編譯的時候就都會發現 為什麼建立 tree 或是做 traversal 的程式碼 總是往左的可以,而往右的部分總是有很奇怪的錯誤..... : 似乎用第一種寫法的人比較多,很多 C++ 大師都是如此。 : 我個人是比較習慣第二種寫法,原因是當有兩個以上的指標: : T *p1, *p2; : 第二種寫法顯然比較合理,這時如果這樣寫: : T* p1, p2; : 那 p2 就不是指標而是物件了。 : 個人認為第二種寫法的最大好處,就是便於理解: : 例如(一律由右往左看): : T *p; // p 是一個指標,指向一個型別 T 的物件 : T &r; // r 是一個 reference,參用一個型別 T 的物件 : 又(同樣一律由右往左看): : T *f(); // f 回傳一個指標,指向型別 T 的物件 : T &g(); // g 回傳一個 reference,參用一型別 T 的物件 : 又(同樣一律由右往左看): : T *const p; // p 是一個 const 指標,指向型別 T 的物件 : T const *p; // p 是一個指標,指向型別 T 的 const 物件 : T const *const p; // p 是一個 const 指標,指向型別 T 的 const 物件 : const T *const p; // 同上(只要保持由右往左讀的習慣,就不會昏頭弄錯) : 甚至(還是由右往左看): : T *const f(); // f 回傳一個 const 指標,指向型別 T 的物件 : T const &g(); // g 回傳一個 reference,參用一個型別 T 的 const 物件 : T *&h(); // h 回傳一個 reference to pointer,參用一指標,該指標指向 : // 一型別 T 的物件 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.70.137.117
sekya:我也是支持T *p,*p2; :p 59.104.35.116 08/20
> -------------------------------------------------------------------------- < 作者: tomex (tomex_ou) 看板: C_and_CPP 標題: Re: [討論] 關於指標記號 * 的位置 時間: Sat Aug 20 23:10:54 2005 C#廢了指標,而用ref變數來取代 強型別的時代是趨勢,也是避免糊模不清的治本方法。 C++喜歡用同個關鍵字代表不同的意義 例如*代表是指標,也代表取值子 對於宣告來說,我是覺得*該偏在type那邊,而不該偏在變數。 重型別的人,將來到java或c#等強型別的語言 是比較容易轉化的。 有人說: int* p1, p2; // p2不是指標 以完全不會語法的人,很容易聯想這語法是要造2個指標的意思 那麼問題並不在於否認人的直觀看法 而是compiler該去修正這樣的宣告誤解才對。 我是從高階語言往低階去學習的 往往能了解高階語言在語意上就是要解決以前不清模糊的地方 或許無法改變低階的現況 但我們學習到新的思想,即使現況作不到,也該堅持正確的直覺宣告法。 compiler並非永遠不標,標準也非永遠不變 而科技始終來自人性,人的直觀法才是取決一切的考量。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.119.52.211
drkkimo:推個 218.164.44.125 08/20
UNARYvvv:最後一行有句話很眼熟 好久沒看到了 61.70.137.117 08/20
> -------------------------------------------------------------------------- < 作者: clifflu (缺錢啦 @@) 看板: C_and_CPP 標題: Re: [討論] 關於指標記號 * 的位置 時間: Sat Aug 20 23:40:05 2005 ※ 引述《tomex (tomex_ou)》之銘言: : 有人說: : int* p1, p2; // p2不是指標 : 以完全不會語法的人,很容易聯想這語法是要造2個指標的意思 : 那麼問題並不在於否認人的直觀看法 : 而是compiler該去修正這樣的宣告誤解才對。 這我就想到一個很好的例子. 在 VB 6.0 中, 如果你使用 Dim Var1, Var2 as String 的話, 你會得到 Var1 (Variant), Var2 (String) (VB 6.0 的 Variant 是種很神妙的型別, 功能和 C: void 或 VB.NET Object 相近) 然而這樣的寫法在 VB.Net 中做了修正, 也就是會將 Var1 和 Var2 的的型態皆設定為 String. 這確實就是 compiler 向某種使用者 "可能" 的習慣作修正. 然而在反面來看, 將 Dim Var1, Var2 as String ^^^^^^^^^^^^^^ 後區視為一個整體, 而前面則是使用預設型別也是有它的道理在. 由此而論, VB.Net 將 Var1, Var2 來視為一個整體反而才是異端邪說了. 所以雖然這樣的寫法可能會比較快, 比較省, 比較優雅, 或甚至有千百種其他的優點, 當一段 code 潛在會被誤認 (ambiguous) 時, 這些寫法都 *應當* 要被其他較不易 出錯, 不容易被誤認, 而能正確執行的碼取代. 畢竟程式碼是給人看的. -- 鬼壓床怎麼辦 騎上去啊 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.212.129
tomex:微軟常常作出貼心的設計,programmer感受的到! 140.119.52.211 08/21
clifflu:XD 貼心是一回事 不過使用者也該自己注意 ^^;;140.112.212.129 08/21
UNARYvvv:這樣看起來應該是一行Dim宣告只能用一種型態囉? 61.70.137.117 08/21
khoguan:VB.Net和舊VB不再相容。MS越來越強勢了 XD220.130.208.168 08/21
clifflu:可以寫成 Dim a as String, b as Integer140.112.212.129 08/21
> -------------------------------------------------------------------------- < 作者: khoguan (Khoguan Phuann) 看板: C_and_CPP 標題: Re: [討論] 關於指標記號 * 的位置 時間: Sun Aug 21 10:16:02 2005 ※ 引述《tomex (tomex_ou)》之銘言: : C++喜歡用同個關鍵字代表不同的意義 : 例如*代表是指標,也代表取值子 C/C++ 關鍵字一字多用的情形,一個明顯的例子就是 static. 在 C 的時代,當他出現在 local scope 的變數宣告前面時, 代表的是 static storage class, 這是 static能夠讓人顧名 思義的用法。但是當它出現在 file scope 的變數宣告前面時, 卻又代表了 internal linkage, 和 static 這個名字難以產生 聯想(file scope 的變數不加 static 本來就已經是 static storage 了,加上 static 對 static storage 並無影響)。 當初如果多個 intern 關鍵字來表示,似乎還比較好。還可以 和 extern 做對比。但 extern 的用法本身似乎也有問題,而且 C++ 的 extern 除了 scope linkage 的用法,還多了 language linkage的用法,就是 extern "C" 這種東東 ..Orz.. 到了 C++ 時代,為了相容,上述用法仍然承襲下來,但是 C++ 標準,已將上述第二種用法標為 deprecated 要人避免使用。 可是另一方面,C++ 又加入了 static 的第三種用法,放在 class member(包含 data 和 function)的宣告前面,表示 它是屬於 class 的 member, 而非屬於個別 class object 的 member. 這和 static 的聯想性也很模糊 ..Orz.. 至於 C++ 所 deprecate 的第二種用法,在 C++ 裡是建議宣告 在 unnamed namespace 來取代。 /* internal.c */ static int internal; // internal.cpp namespace { //... int internal; } 這種 unnamed namespace 似乎很少人想去利用。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.130.208.168
UNARYvvv:我剛想到class,typename不同地方也有不同用處XD 61.70.137.117 08/21
khoguan:嗯,是的。我也有想到 ^_^220.130.208.168 08/21
> -------------------------------------------------------------------------- < 作者: renderer (rendering) 看板: C_and_CPP 標題: Re: [討論] 關於指標記號 * 的位置 時間: Sun Aug 21 11:33:40 2005 關於指標記號 * 的位置 在這個地方: unsigned int value; int* v = (int*) &value; ~~~~~~ int* 是個型別 所以好像 * 向型別靠比較好 但在這個地方: void (*fun_ptr) (); ~~~~~~~~~~ fun_ptr 是個指標 所以好像 * 向變數靠比較好 呵呵 一笑 看來向哪邊靠似乎都不會有一個比較統一的標準思維 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.228.217.108 ※ 編輯: renderer 來自: 61.228.217.108 (08/21 11:34) > -------------------------------------------------------------------------- < 作者: renderer (rendering) 看板: C_and_CPP 標題: Re: [討論] 關於指標記號 * 的位置 時間: Sun Aug 21 11:42:13 2005 又想到一些例子 int* const value; // 向型別靠好 向變數沒得靠 int (*value)[10]; // 向變數靠好 向型別沒得靠 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.228.217.108
khoguan:適合靠哪邊就靠哪邊,沒得靠就靠自己。正所謂220.130.208.168 08/21
khoguan:此身飲罷無歸處,獨立蒼茫自詠詩。220.130.208.168 08/21
renderer:大概就是這樣了: 61.228.217.108 08/21
renderer:int const * const value; 61.228.217.108 08/21
renderer:k大是讀什麼科系的呢 感覺頗有文才 61.228.217.108 08/21
khoguan:摭拾古人牙慧,褻瀆了詩聖,真不好意思。220.130.208.168 08/21
simata:可以改成 int* value const; 嗎??? 59.112.230.24 08/25
simata:若可..即可以變成 int *value const; :P 59.112.230.24 08/25
> -------------------------------------------------------------------------- < 作者: renderer (rendering) 看板: C_and_CPP 標題: Re: [討論] 關於指標記號 * 的位置 時間: Sun Aug 21 16:55:55 2005 「T* d」 說不清楚的例子: int *data0, *data1; 「T *d」 說不清楚的例子: int* data[2]; C++ 的變數宣告語法是強調 usage 而不是 type 例如: int * data [3][5]; 其 usage 修飾強度順序是: int * data [3][5]; 4 3 0 1 2 所以使用時: data 的型別是 int * [3][5] data[0] 的型別是 int * [5] data[0][1] 的型別是 int * *data[0][1] 的型別是 int 又例如: void (*fun_ptr) (int, int); 使用時: fun_ptr 的型別是 void (*) (int, int) *fun_ptr 的型別是 void () (int, int) 強調 usage 的宣告語法暗示了我們要怎麼去使用變數 基於這一點寫 int *data; 是合理的 因為 *data 代表 int 而讓 * 靠著 data 似乎滿好的 然而強調 type 的宣告方式似乎也滿自然的 如果使用 型別 變數; 這樣子的宣告格式 會讓我們清楚地知道變數的型別 而在 型別轉換 與 new 的使用時 會得到一個型別清晰的方便性 如: int* data; data = (int*) value; 與 int** data; data = new int*; 基於這點:想清楚地表達型別 而讓 * 靠著型別似乎也是出乎天性 語言本身似乎無意讓 * 偏靠哪一邊 而人卻有心要讓 * 偏靠哪一邊 畢竟 int * data; 的宣告似乎多用了個 ' ' 要少用一個 ' ' 不靠型別 就得靠變數了 ----------------- 以下是閒談 ------------------ 小弟個人目前的結論是: 看哪樣子好看、清楚,就那麼靠吧;都不好看的話,就都不靠啦。 如: int *data0, *data1; int* data[2]; int const * const data; -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 61.228.217.108