2008-11-05 106 views
24

我總是儘量避免返回字符串文字,因爲我擔心它們沒有在函數外部定義。但我不確定是否是這種情況。例如,我們來看看這個功能:(字符串)文字的範圍


const char * 
return_a_string(void) 
{ 
    return "blah"; 
} 

這是正確的代碼嗎?它對我有用,但也許它只適用於我的編譯器(gcc)。所以問題是,do(字符串)文字是否有範圍,或者它們是否始終存在/定義。

回答

35

這段代碼在所有平臺上都很好。該字符串被編譯爲二進制文件作爲靜態字符串文字。如果你在windows上,你甚至可以用記事本打開你的.exe文件,然後搜索字符串本身。

由於它是一個靜態字符串,字面範圍並不重要。

字符串池:

一件事看出來的是,在某些情況下,相同的字符串文字可以被「合併」,以節省空間的可執行文件。在這種情況下,每個相同的字符串文字可能具有相同的內存地址。你永遠不應該認爲它會或不會是這樣。

在大多數編譯器中,您可以設置是否將靜態字符串池用於stirng文字。

字符串文字的最大尺寸:

一些編譯器對字符串文字的最大尺寸。例如對於VC++,這大約是2048字節。

修改字符串字面給人未定義行爲:

修改字符串文字不應該做。它有一個未定義的行爲。

char * sz = "this is a test"; 
sz[0] = 'T'; //<--- undefined results 

寬字符串文字:

所有的上述同樣適用於寬字符串文字。

例如:L「這是一個寬字符串」;

C++標準狀態:(部分lex.string)

1字符串文字是由雙引號所包圍的字符序列 (如在 lex.ccon定義),任選從 字母L開始,如「...」或L「...」中所示。不與L一起開始 的字符串文字是普通的字符串文字,也被稱爲窄字符串文字。普通字符串文字具有類型和靜態存儲持續時間(basic.stc),其中n是如下面所定義,並且與給定的字符 初始化字符串的大小 「N 常量 char數組」。以L開頭的字符串文字,例如L「asdf」, 是寬字符串文字的 。寬字符串文字的類型爲「數組 n const wchar_t」並且具有靜態存儲持續時間,其中n是大小爲 的 字符串(如下定義),並使用給定的字符串進行初始化。

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

+0

既然你明確提到寬字符串文字,每做文字表現呀?隨着每一次我指的是C99複合文字。 – quinmars 2008-11-05 23:56:26

2

是的,沒關係。他們住在一個全局的字符串表中。

2

不,字符串文字沒有範圍,所以您的代碼可以保證在所有平臺和編譯器中都可以工作。它們存儲在程序的二進制圖像中,因此您可以隨時訪問它們。但是,試圖寫信給他們(通過丟棄const)將導致未定義的行爲。

0

實際上,您會返回一個指向存儲在可執行文件的數據部分中的零終止字符串的指針,該區域在加載程序時加載。只要避免嘗試和改變字符,它可能會給出不可預知的結果...

0

注意到Brian提到的未定義結果是非常重要的。既然你已經聲明函數返回一個const char *類型,你應該沒問題,但是在許多平臺上,字符串文字被放到可執行文件(通常是文本段)的只讀段中,並修改它們會導致訪問衝突在大多數平臺上。

2

正如其他人所解釋的,這在C(或C++)中是有效的。

我能想到的一件事就是如果你使用dll,那麼如果包含這段代碼的dll被卸載,指針將不會保持有效。 C(或C++)標準並不理解或考慮在運行時加載和卸載代碼,因此任何做這些都會面臨實現定義的後果:在這種情況下,結果是字符串文字應該具有靜態存儲持續時間,從調用代碼的POV中出現不會持續整個程序的持續時間。

7

我給你舉個例子,這樣你的困惑變得有些清晰

char *f() 
{ 
char a[]="SUMIT"; 
return a; 
} 

這不會工作。

char *f() 
{ 
char *a="SUMIT"; 
return a; 
} 

這個工程。

原因:「SUMIT」是一個具有全局範圍的文字。而數組只是字符序列{'S','U','M','I','T''\ 0'} 的範圍有限,並且只要程序是返回。

希望這有助於