簡體   English   中英

為什么更改非const char *的分段錯誤?

[英]Why a segmentation fault for changing a non-const char*?

使用此代碼,我得到一個分段錯誤:

   char* inputStr = "abcde";
   *(inputStr+1)='f';

如果代碼是:

   const char* inputStr = "abcde";
   *(inputStr+1)='f';

我將收到“分配只讀位置”的編譯錯誤。 但是,對於第一種情況,沒有編譯錯誤; 只是分配操作實際發生時的分段錯誤。

有誰能解釋一下?

以下是標准中關於字符串文字的內容[2.13.4 / 2]:

不以u,U或L開頭的字符串文字是普通的字符串文字,也稱為窄字符串文字。 普通的字符串文字具有“n const char數組”類型,其中n是下面定義的字符串的大小; 它具有靜態存儲持續時間(3.7)並使用給定的字符進行初始化。

所以,嚴格來說,“abcde”有類型

const char[6]

現在你的代碼中發生的是隱式轉換

char*

以便允許分配。 其原因可能是與C的兼容性。另請參閱此處的討論: http//learningcppisfun.blogspot.com/2009/07/string-literals-in-c.html

一旦完成轉換,你在語法上可以自由地修改文字,但它失敗了,因為編譯器將文字存儲在不可寫的內存段中,正如標准本身所允許的那樣。

這是在代碼段中創建的:

char *a = "abcde";

基本上它是常量。

如果您想編輯它,請嘗試:

char a[] = "abcde";

該標准規定,不管您是否將它們標記為const ,都不允許直接修改字符串文字:

是否所有字符串文字都是不同的(即存儲在非重疊對象中)是實現定義的。 嘗試修改字符串文字的效果是未定義的。

實際上,在C語言中(與C ++不同),字符串文字不是 const但仍然不允許您寫入它們。

這種寫作限制允許進行某些優化,例如按以下方式共享文字:

char *ermsg = "invalid option";
char *okmsg =   "valid option";

其中okmsg實際上可以指向'v'字在ermsg ,而不是一個不同的字符串。

字符串文字通常存儲在只讀存儲器中。 試圖更改此內存將導致程序中斷。

這里有一個很好的解釋: c ++中的字符串文字是在靜態內存中創建的嗎?

這主要是古代歷史; 很久以前,字符串文字並不是一成不變的。

但是,大多數現代編譯器將字符串文字放入只讀內存(通常是程序的文本段,代碼也存在),任何更改字符串文字的嘗試都會產生核心轉儲或等效內容。

使用G ++,您當然可以獲得編譯警告(如果默認情況下未啟用,則為-Wall )。 例如,在MacOS X 10.6.7上編譯的G ++ 4.6.0(但在10.7上運行)產生:

$ cat xx.cpp
int main()
{
    char* inputStr = "abcde";
   *(inputStr+1)='f';
}
$ g++ -c xx.cpp
xx.cpp: In function ‘int main()’:
xx.cpp:3:22: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
$

因此默認情況下啟用警告。

發生的事情是編譯器將常量"abcde"放在某個只讀內存段中。 您將(非常量) char* inputStr指向該常量,並將kaboom,segfault指向。

要學習的課程:不要調用未定義的行為。

編輯(闡述)

但是,對於第一種情況,沒有編譯錯誤,只是在分配操作實際發生時分段錯誤。

您需要啟用編譯器警告。 始終將編譯器警告設置得盡可能高。

在里奇的話中,有一點關於字符串文字的歷史。 主要是關於orgin和來自K&R的字符串文字的演變1.希望這可能澄清關於const和字符串文字的一兩件事。

“來自:Dennis Ritchie主題:回復:歷史問題:字符串文字。日期:1998年6月2日新聞組:comp.std.c

在C89委員會工作的時候,可寫字符串文字不是“遺留代碼”(Margolin),並且存在的標准(K&R 1)非常明確(A.2.5)字符串只是初始化靜態的一種方式陣列。 正如Barry指出的那樣,有一些(mktemp)例程使用了這個事實。

我不是委員會關於這一點的討論,但我懷疑BSD實用程序用於擺弄匯編程序代碼以將字符串的初始化移動到文本而不是數據,並且認識到大多數文字字符串實際上沒有被覆蓋,比一些早期版本的gcc更重要。

在那里我認為委員會可能錯過了某些東西,但未能找到一個用const來解釋字符串文字行為的公式。 也就是說,如果“abc”是一個類型為const char [4]的匿名文字,那么它的所有屬性(包括只讀,甚至與其他同一文字的存儲共享其存儲的能力)都是差點解釋。

這個問題不僅是字符串文字實際編寫的相對較少的地方,更重要的是,制定了指向const的指針的可行規則,特別是函數的實際參數。 實際上,委員會知道他們制定的任何規則都不需要對現有世界中的每個功能(“字符串”)進行必要的診斷。

所以他們決定留下普通字符數組類型的“......”,但是說要求一個人不要寫它。

本說明BTW不打算在C89的配方中作為狙擊手閱讀。 很難讓事情正確(連貫和正確)和可用(足夠一致,足夠吸引人)。

Dennis

盡管"abcde"是一個不應該被修改的字符串文字,但是你告訴編譯器你不關心它,因為有一個非const char*指向它。

編譯器很樂意假設您知道自己在做什么,而不是拋出錯誤。 但是,當您確實嘗試修改字符串文字時,代碼很可能在運行時失敗。

字符串文字雖然官方非常量,但幾乎總是存儲在只讀內存中。 在你的設置中,顯然只有它被聲明為const char數組的情況。

請注意,標准禁止您修改任何字符串文字。

暫無
暫無

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

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