Re: [問題] const 二維指標陣列參數傳遞問題

看板C_and_CPP (C/C++)作者 (小西風最乖了*^^*)時間14年前 (2011/07/28 22:29), 編輯推噓4(406)
留言10則, 4人參與, 最新討論串2/2 (看更多)
警告:這篇有冗長的討論跟難懂的標準。 ※ 引述《tropical72 (藍影)》之銘言: : --------- : #include <string.h> <cstring> ? : class Object{ : public: : int value; : }; : void f1( const Object * const obj[6] ){} : void f2( const Object * const obj[6][6]){} 首先要知道 f1, f2 的型態到底是什麼。 f1 的參數的型態表面上是 array of 6 const-qualified pointers to const-qualified Objects f2 的參數的型態表面上是 array of 6 arrays of 6 const-qualified pointers to const-qualified Objects 但是這是假象,因為... | .... After determining the type of each parameter, any | parameter of type "array of T" or "function returning T" | is adjusted to be "pointer to T" or "pointer to function | returning T," respectively. After producing the list of | parameter types, several transformations take place upon | these types to determine the function type. Any cv-qualifier | modifying a parameter type is deleted. .... @ C++ 8.3.5 / 3 f1(對外)的型態會變成 void (const Object * const *) pointer to const-qualified pointer to const-qualified Objects f2(對外)的型態會變成 void (const Object * const (*) [6]) pointer to array of 6 const-qualified pointers to const-qualified Objects 我個人的解讀是 C/C++ 在無數場合都會自動把陣列轉型成指標,所以函 式型態區分兩者本來就沒啥意義。 : int main() : { : Object *obj1[6]; : f1( obj1 ); 這個自動(標準)轉型我就不贅言了。 : /* L1 */ : // Visual C++ - error C2664: : // 無法將參數 1 從 'Object *[6][6]' 轉換成 'const Object *const [][6] : Object *obj2[6][6]; : f2(obj2); obj2 的型態是: array of 6 array of 6 pointer to Object 在這裡用的時候可以幫你用「陣列轉指標」先轉型成: pointer to array of 6 pointers to Object 頂多再根據「cv 自動轉換」轉型成: pointer to array of 6 const-qualified pointer to Object 可是 f2 要的是 pointer to array of 6 const-qualified pointer to const-qualified Object 原因是有礙事的陣列所以沒辦法轉過去。就算陣列這裡變成指標也不行, 詳情見 http://c-faq.com/ansi/constmismatch.html (裡面有提到C++03) : /* L2 - I know it's error...*/ : typedef const Object* pObj[6][6]; : f2((pObj)obj2); typedef 是用來精確(感覺用字怪怪的)指稱一個型態,不會有上述指標 陣列的轉換。這裡最大問題是沒辦法轉型成陣列。但指標之間可以互轉,而且 陣列在很多地方會自動轉型成指標(警告:請看結尾個人對標準的抱怨。可以 轉型不代表轉型會「成功」)。所以你可以寫: | typedef const Object* const (*pObj)[6]; | f2((pObj)obj2); 或是如果有人熱愛 C++ 的新轉型寫法的話... | f2(reinterpret_cast<pObj>(obj2)); (注意這裡跟 const_cast 一點關係也沒有!有點懶得解釋 orz 主要是因 為卡了一個陣列在中間。) : /* L3 */ : const Object *tmp[6][6]; : memcpy(tmp, obj2, sizeof(Object)*36); : f2(tmp); 這個嘛... 我不是 200% 確定標準有沒有保證複製過去後是不是代表同樣 的值(請看結尾個人對標準的抱怨)。就算都可以好了,建議寫成 sizeof(tmp) 減少可能的打字錯誤。 : return 0; : } : ------- : L1 的部份是錯誤訊息, 我模糊了為何不能過, : 改成 const Object *obj2[6][6] 確實可以, : 但以為 non-const 可以丟給 const做傳遞動作。 這裡 obj2 的型態是: array of 6 array of 6 pointer to const-qualified Object 在這裡用的時候可以幫你用「陣列轉指標」先轉型成: pointer to array of 6 pointer to const-qualified Object 再根據「cv 自動轉換」轉型成: pointer to array of 6 const-qualified pointer to const-qualified Object 跟 f2 要的一樣。 : L2 部份是我的 trying, : 我其實是想再 typedef pObj 成 const obj* [6][6], : 再強制轉型, 這部份不知該如何下手 : L3 這是原提問者用的想法、概念 (code依概念寫的) : 想請問這問題,在不動 f2 情況下,obj2 該怎麼丟到 f2 執行? : 謝謝各位不吝指教, 感激不盡! 希望全部問題都有回答到了 xD 我很好奇上色到底有沒有幫助? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.30.39

07/28 22:52, , 1F
感謝解惑 :)
07/28 22:52, 1F

07/28 22:53, , 2F
補上,上色是有幫助的.另我想額外問,除了強制轉型外,
07/28 22:53, 2F

07/28 22:54, , 3F
目前這問題是否就因(規格書定義),可能暫時沒其它解法?
07/28 22:54, 3F
剛才想到,複製一份程式碼,或是用模板如何 xD 這看起來是最安全(?) 的作法了。 === 補一下個人對標準的抱怨: 我個人沒有看到標準 200% 明確指出指標轉型或 memcpy 會成功,只能說合 理的實作應該都沒問題 orz 這牽扯到一些很無聊的瑣碎定義(希望新標準有好 一點)。關鍵在標準(C++03)用了「layout 相容」和「representation 相同」 努力說明兩個東西是一樣的。可是即使 representation 一樣,我也沒有找到條 文說這代表 layout 相容、可以用 memcpy 或是用 reinterpret_cast 轉型保證 成功。雖然我個人實在想不出來,當 representation 都一樣的時候為什麼這些 會不能用,不過我真的找不到條文... 所以不太敢說沒有問題。當然啦,我現在 自己用的電腦都是完全吻合的(根據其他標準或實作文件)。 === 補上一些相關問題(來自 tropical72) | T * * --> const T * const * 可以轉 見 http://c-faq.com/ansi/constmismatch.html (裡面有提到 C++03) | T * array --> const T * const array 卻不能轉 囧 我想根本原因是陣列本來就不能轉... 一般看起來有轉,實際上是指標轉型。 ※ 編輯: Favonia 來自: 140.112.30.39 (07/29 01:02)

07/29 00:23, , 4F
我覺得比較好的做法是把陣列封裝在物件中
07/29 00:23, 4F

07/29 00:24, , 5F
避免陣列decay成pointer造成這類困擾
07/29 00:24, 5F

07/29 00:24, , 6F
改成物件對於程式碼的可讀性也有幫助
07/29 00:24, 6F
我想引用 C++ 發明人的話。我想他的意見跟你完全一樣 :P(我的意見大概 只會比他更多 xDDDD) | That is, why does C++ support operations that can be used to violate | the rules of static (compile-time) type safety? (略過他講的原因,以下是他講的「但書」 xD) | That said, it is a good idea to avoid unsafe code like the plague | whenever you don't actually need one of those three features: | > don't use casts | > keep arrays out of interfaces (hide them in the innards of high- | performance functions and classes where they are needed and write | the rest of the program using proper strings, vectors, etc.) (略) | Almost all C++ code can follow these simple rules. Please don't be | confused by the fact that you cannot follow these rules if you write | C code or C-style code in C++. @ http://www2.research.att.com/~bs/bs_faq.html ※ 編輯: Favonia 來自: 140.112.30.39 (07/29 01:09)

07/29 01:10, , 7F
請愛用std::array謝謝
07/29 01:10, 7F

07/29 01:12, , 8F
泛型加下去就對了
07/29 01:12, 8F
雖然我不知道 C++0x 已經多流行了,但我想用模板來做應該不是壞事 :) ※ 編輯: Favonia 來自: 140.112.30.39 (07/29 01:14)

07/29 01:14, , 9F
謝謝各位解釋與指導,受益良多,再次感謝 *^_^*
07/29 01:14, 9F
※ 編輯: Favonia 來自: 140.112.30.39 (07/29 01:17)

07/29 09:01, , 10F
目前還是似懂非懂,copy回家,有空慢慢想
07/29 09:01, 10F
※ 編輯: Favonia 來自: 140.112.30.39 (07/29 20:39) ※ 編輯: Favonia 來自: 140.112.30.39 (07/30 10:29) 編輯:抱歉 obj2 的型態之前腦殘打錯了!那邊整段重寫。 編輯:所以另外加上一段解釋為什麼加上一個 const 可以。 編輯:改引用 c-faq. ※ 編輯: Favonia 來自: 140.112.30.39 (07/30 19:38) 編輯:「陣列轉指標」打成「指標轉陣列」orz ※ 編輯: Favonia 來自: 140.112.30.39 (07/31 04:55) 編輯:這似乎是一個標準的缺陷。標準委員會已經注意到這個問題: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#330 ※ 編輯: Favonia 來自: 140.112.30.39 (08/02 05:37)
文章代碼(AID): #1ECN91Ym (C_and_CPP)
文章代碼(AID): #1ECN91Ym (C_and_CPP)