這是我的理解是這樣的事情是好的:int **和const int **可以替代別名嗎?
const int ci = 42;
const int *cip = &ci;
int *ip = (int *)cip;
int j = *ip;
這個怎麼樣?
const int ci = 42;
const int *cip = &ci;
const int **cipp = &cip;
int **ipp = (int **)cipp;
int j = **ipp;
這是我的理解是這樣的事情是好的:int **和const int **可以替代別名嗎?
const int ci = 42;
const int *cip = &ci;
int *ip = (int *)cip;
int j = *ip;
這個怎麼樣?
const int ci = 42;
const int *cip = &ci;
const int **cipp = &cip;
int **ipp = (int **)cipp;
int j = **ipp;
表達*ipp
int *
是類型的左值,然而它正用於訪問有效類型的const int *
的對象。 (即,cip
)。
根據該標準的字母,它是嚴格的別名違規:允許的別名類型的列表不包括別名T *
作爲const T *
,反之亦然。
最接近的例外是這一個:(C11 6.5/6摘錄)
- 與有效類型的對象
的兼容的類型的一個合格的版本「合格版本「由C11 6.2.5/26明確定義:
每個不合格類型有幾個合格版本其類型,對應於
const
,volatile
和restrict
限定符中的一個,兩個或全部三個的組合。類型的合格或不合格 版本是屬於相同類型類別且具有相同表示和對齊要求的不同類型。派生類型不符合派生類型的限定符(如果有)。
所以異常是T
可別名爲const T
,反之亦然,但目前還沒有類似的例外指針aliasable類型。 const T *
不是合格版本的T *
。
然而當然還有的註腳:
這種情況下這份名單的目的是,以指定的對象可能會或可能不會被混淆
我不能」說明規則的意圖是否爲const T *
和T *
是可以別名的。對我來說,如果指定T *
和const T *
具有「相同的表示和對齊要求」(6.2.5/28),如果它不是可以混淆的,這似乎還不清楚。
保證只有在被視爲別名規則的例外時纔有用,這一事實不再意味着編譯器編寫者會將其解釋爲一個。除非在「沒有嚴格別名」模式下,通用初始序列保證在gcc和clang下基本沒有用處。前面已經說過,無論編譯器*還是*都假定'int * p'不會使用'int const ** p'來訪問,反之亦然;我不知道這是否會保持真實。 – supercat
int * ip =(int *)cip;'不好。你的編譯器應該抱怨丟掉'const'。如果不使用更高的警告等級。或者你想要什麼樣的「確定」? 「作品」,「可靠地工作」,「可移植作品」,「是很好的代碼」,... – Yunnosch
@ Yunnosch:不。顯式強制轉換實際上就是你如何告訴編譯器你真的想要拋棄const。這就是你告訴編譯器不要發出任何警告的方式。第一個代碼片段是完全合法的C. – AnT
@AnT對於所示的代碼,不需要去掉const。對於其他代碼有一個目的不是一個好主意。然而,我承認,我將編譯器警告與明確超級嚴格的靜態代碼分析器生成的nitpicky警告相混淆;我將在工作中用於代碼。他們不僅需要演員才能停止嘮叨。這有點讓我思考。 – Yunnosch