簡體   English   中英

為什么將“指向非常量的指針的指針”轉換為“指向常量的指針的指針”是不合法的

[英]Why isn't it legal to convert "pointer to pointer to non-const" to a "pointer to pointer to const"

將指向非常量的指針轉換為指向常量的指針合法的。

那么為什么將指向非 const指針的指針轉換為指向 const指針的指針是不合法的呢?

例如,為什么下面的代碼是非法的:

char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char **ps = a; // error!

從標准:

const char c = 'c';
char* pc;
const char** pcc = &pc;   // not allowed
*pcc = &c;
*pc = 'C';                // would allow to modify a const object

忽略您的代碼並回答您的問題的原則,請參閱 comp.lang.c 常見問題解答中的此條目:為什么我不能將 char ** 傳遞給需要 const char ** 的函數?

不能將char **值分配給const char **指針的原因有些模糊。 鑒於const限定符完全存在,編譯器希望幫助您遵守不修改const值的承諾。 這就是為什么您可以將char *分配給const char * ,而不是相反:將const -ness“添加”到一個簡單的指針顯然是安全的,但將其刪除會很危險。 但是,假設您執行了以下更復雜的一系列作業:

 const char c = 'x'; /* 1 */ char *p1; /* 2 */ const char **p2 = &p1; /* 3 */ *p2 = &c; /* 4 */ *p1 = 'X'; /* 5 */

在第 3 行,我們將char **分配給const char ** (編譯器應該抱怨。)在第 4 行,我們將const char *分配給const char * 這顯然是合法的。 在第 5 行,我們修改了char *指向的內容——這應該是合法的。 但是, p1最終指向c ,即const 這出現在第 4 行,因為*p2實際上是p1 這是在第 3 行中設置的,這是一個被禁止的表單的分配,這正是第 3 行被禁止的原因。

由於您的問題被標記為 C++ 而不是 C,它甚至解釋了要使用的const限定符:

(C++ 有更復雜的分配 const 限定指針的規則,這使您可以在不產生警告的情況下進行更多類型的分配,但仍然可以防止無意中嘗試修改 const 值。C++ 仍然不允許將char **分配給const char ** ,但它會讓您擺脫將char **分配給const char * const * 。)

就因為沒有人發布解決方案,這里:

char *s1 = 0;
const char *s2 = s1; // OK...
char *a[MAX]; // aka char **
const char * const*ps = a; // no error!

http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17為什么)

C++11 草案標准在第4.4節的注釋中解釋了這一點,其中說:

[注意:如果程序可以將 T** 類型的指針分配給 const T** 類型的指針(即,如果允許下面的第 1 行),則程序可能會無意中修改 const 對象(因為它已完成)在第 2 行)。 例如,

 int main() { const char c = 'c'; char* pc; const char** pcc = &pc; // #1: not allowed *pcc = &c; *pc = 'C'; // #2: modifies a const object }

——尾注]

一個有趣的相關問題是Given int **p1 和 const int **p2 is p1 == p2 wellformed? .

請注意, C++ FAQ對此也有解釋,但我更喜歡標准中的解釋。

與注釋一致的文本如下:

轉換可以在多級指針的第一個以外的級別添加 cv 限定符,遵循以下規則:56

如果存在類型 T 和整數 n > 0 使得兩個指針類型 T1 和 T2 相似:

T1 是 cv1,0 指向 cv1,1 的指針指向 · · · cv1,n−1 指向 cv1,n 的指針 T

T2 是 cv2,0 指向 cv2,1 的指針指向 · · · cv2,n−1 指向 cv2,n 的指針 T

其中每個 cvi,j 是 const、volatile、const volatile 或什么都沒有。 指針類型中第一個之后的 cv 限定符的 n 元組,例如,指針類型 T1 中的 cv1,1, cv1,2, · · · , cv1,n,稱為指針類型的 cv 限定簽名. 當且僅當滿足以下條件時,類型 T1 的表達式才能轉換為類型 T2:

  • 指針類型相似。
  • 對於每個 j > 0,如果 const 在 cv1,j 中,那么 const 在 cv2,j 中,對於 volatile 也是如此。
  • 如果 cv1,j 和 cv2,j 不同,則 const 在每個 cv2,k 中,因為 0 < k < j。

這里有兩條規則需要注意:

  • 如果 T 和 U 是不同的類型,則 T T*U*之間沒有隱式轉換。
  • 您可以隱式地將T*T const * (“指向 T 的指針”可以轉換為“指向 const T 的指針”)。 在 C++ 中,如果T也是指針,那么這個規則也可以應用於它(鏈接)。

例如:

char**表示:指向 char 指針的指針

const char**意味着:指向 const char 指針的指針

由於指向 char 的指針指向 const char 的指針是不同的類型,僅在常量性方面不同,因此不允許進行強制轉換。 要強制轉換的正確類型應該是指向 char 的 const 指針

因此,要保持 const 正確,您必須從最右邊的星號開始添加 const 關鍵字。

所以char**可以轉換為char * const * ,也可以轉換為const char * const *

此鏈接僅適用於 C++。 在 C 中,這種鏈接不起作用,因此在該語言中,您不能正確地轉換多於一層的指針 const。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM