Re: [問題] const 二維指標陣列參數傳遞問題
看板C_and_CPP (C/C++)作者Favonia (小西風最乖了*^^*)時間14年前 (2011/07/28 22:29)推噓4(4推 0噓 6→)留言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
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
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
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)
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 2 之 2 篇):
C_and_CPP 近期熱門文章
PTT數位生活區 即時熱門文章