2008-09-16 213 views
55

下面的代碼段(正確地)給出在C語言的警告和錯誤在C++(使用gcc &克++分別與3.4.5和4.2.1版本測試; MSVC似乎並不關心):爲什麼我不能在C中將'char **'轉換爲'const char * const *'?

char **a; 
const char** b = a; 

我可以理解並接受這一點。
此問題的C++解決方案是將b更改爲const char * const *,它禁止重新分配指針並阻止您規避const正確性(C++ FAQ)。

char **a; 
const char* const* b = a; 

然而,在純C,修正版本(中使用const char * const的*)還給出了一個警告,我不明白爲什麼。 有沒有辦法避免這種情況而不使用強制轉換?

澄清:
1)爲什麼這會在C中產生警告?它應該完全是常量安全的,而C++編譯器似乎也是這樣認識的。
2)接受這個char **作爲參數的正確方法是什麼,同時說(並讓編譯器強制執行)我不會修改它指向的字符? 例如,如果我想編寫一個函數:

void f(const char* const* in) { 
    // Only reads the data from in, does not write to it 
} 

,我想調用它在一個char **,什麼是正確的類型參數?

編輯: 非常感謝那些已經回覆的人,特別是那些回答問題和/或跟進我的回覆的人。

我已經接受了答案,即我不想在沒有演員的情況下做我想做的事,不管它是否應該是可能的。

+0

我對你的問題感到困惑,是這樣的:「我如何讓C不警告我?」還是「我如何讓C++不會拋出編譯錯誤?」或者,也許它們都不是這些。 – user7116 2008-09-16 22:55:12

+0

我同意sixlettervariables,這個問題需要進一步澄清。 – 2008-09-16 23:00:18

+0

問題是「爲什麼我不能將'char **'轉換爲'char * const *?' – Kevin 2008-09-16 23:05:53

回答

53

幾年前,我也遇到了同樣的問題,它讓我感到無法接受。

C中的規則更簡單地陳述(即,它們沒有列出例如將char**轉換爲const char*const*的例外)。結果,這只是不被允許的。在C++標準中,它們包含了更多的規則來允許這樣的情況。

最後,這只是C標準中的一個問題。我希望下一個標準(或技術報告)能解決這個問題。

11

>然而,在純C,這仍然給出了一個警告,我不明白爲什麼

你已經發現了問題 - 這個代碼是不是常量,正確的。 「Const correct」意思是說,除了const_cast和C-style強制刪除const之外,你永遠不能通過這些const指針或引用來修改一個const對象。

常量正確性的值 - const在很大程度上是爲了檢測程序員錯誤。如果你將某些東西聲明爲const,那麼你就說你不認爲它應該被修改 - 或者至少,那些有權訪問const版本的人不應該修改它。試想一下:

void foo(const int*); 

至於宣佈,富沒有許可修改整數通過它的參數指向。

如果你不知道你爲什麼發佈的代碼不是const的,正確的,考慮下面的代碼,僅從HappyDude的代碼稍有不同:

char *y; 

char **a = &y; // a points to y 
const char **b = a; // now b also points to y 

// const protection has been violated, because: 

const char x = 42; // x must never be modified 
*b = &x; // the type of *b is const char *, so set it 
     //  with &x which is const char* .. 
     //  .. so y is set to &x... oops; 
*y = 43; // y == &x... so attempting to modify const 
     //  variable. oops! undefined behavior! 
cout << x << endl; 

非const類型只能轉換爲常量以特定的方式來防止在沒有明確強制轉換的情況下對數據類型的'const'進行規避。

最初聲明const的對象特別特別 - 編譯器可以假定它們永遠不會改變。然而,如果'b'可以在沒有強制轉換的情況下分配'a'的值,那麼你可能會不經意地嘗試修改一個const變量。這不僅會中斷您要求編譯器進行的檢查,不允許您更改該變量值 - 它還會允許您中斷編譯器優化!

在某些編譯器上,這將打印'42',在某些'43'和其他文件上,程序將崩潰。

編輯相加:

HappyDude:您的評論是即期。無論是C語言還是您使用的C編譯器,對待const char * const *的處理方式都與C++語言的處理方式根本不同。也許可以考慮只沉默這個源代碼行的編譯器警告。

編輯,刪除:刪除錯字

0

我不能夠得到一個錯誤,當隱式鑄造焦炭**爲const char * const的*,至少在MSVC 14(VS2k5)和g ++ 3.3。 3。 GCC 3.3.3發出警告,我不確定它是否正確。

test.c的:

#include <stdlib.h> 
#include <stdio.h> 
void foo(const char * const * bar) 
{ 
    printf("bar %s null\n", bar ? "is not" : "is"); 
} 

int main(int argc, char **argv) 
{ 
    char **x = NULL; 
    const char* const*y = x; 
    foo(x); 
    foo(y); 
    return 0; 
} 

輸出與編譯爲C代碼:CL/TC/W4/Wp64 test.c的

test.c(8) : warning C4100: 'argv' : unreferenced formal parameter 
test.c(8) : warning C4100: 'argc' : unreferenced formal parameter 

輸出與編譯作爲C++代碼:CL/TP/W4/Wp64 test.c的

test.c(8) : warning C4100: 'argv' : unreferenced formal parameter 
test.c(8) : warning C4100: 'argc' : unreferenced formal parameter 

輸出用gcc:GCC -Wall test.c的

test2.c: In function `main': 
test2.c:11: warning: initialization from incompatible pointer type 
test2.c:12: warning: passing arg 1 of `foo' from incompatible pointer type 

輸出與克++:克++ -Wall TEST.C

沒有輸出

0

我很肯定的是,關鍵字const並不意味着該數據不能被改變/是恆定的,只有數據將被視爲只讀。考慮這個:

const volatile int *const serial_port = SERIAL_PORT; 

這是有效的代碼。 volatile和const如何共存?簡單。 volatile指示編譯器在使用數據時總是讀取內存,而const在使用serial_port指針嘗試寫入內存時告訴編譯器創建錯誤。

const是否幫助編譯器的優化器?一點都不。因爲通過強制轉換可以將常量添加到數據中或從中刪除,因此編譯器無法弄清楚const數據是否真的是常量(因爲可以在不同的翻譯單元中進行強制轉換)。在C++中,你也有可變關鍵字使事情進一步複雜化。

char *const p = (char *) 0xb000; 
//error: p = (char *) 0xc000; 
char **q = (char **)&p; 
*q = (char *)0xc000; // p is now 0xc000 

時試圖寫這確實是只讀(ROM,例如)內存會發生什麼可能未在標準中定義的。

9

要被認爲是兼容的,源指針應該是在緊鄰前間接級別的const。所以,這會給你在GCC警告:

char **a; 
const char* const* b = a; 

但這不會:

const char **a; 
const char* const* b = a; 

或者,你可以將它轉換:

char **a; 
const char* const* b = (const char **)a; 

您需要同按照你所說的轉換來調用函數f()。據我所知,在這種情況下無法進行隱式轉換(C++除外)。

1

這是惱人的,但如果你願意加入重定向的另一個層面上,你可以經常下向下推入指針到指針:

char c = 'c'; 
char *p = &c; 
char **a = &p; 

const char *bi = *a; 
const char * const * b = &bi; 

它有一個稍微不同意思是,但它通常是可行的,並且它不使用演員。

相關問題