2009-11-20 41 views
0

here它表示,對於全局變量的格式如下:定義指針靜態字符串

(1) const char *a = "..."; 

是不太好的比:

(2) const char a[] = "..." 

爲什麼?我始終認爲,(1)是更好的,因爲(2)實際上覆制我們給它,而(1)僅指向它的字符串。

+0

另見我的回答對您的[前一個問題] [^ 1]爲什麼最好使用數組與指針。 [^ 1]:http://stackoverflow.com/questions/1769089/defining-const-pointer-to-a-const-string/1769163#1769163 – LnxPrgr3 2009-11-20 17:30:10

回答

3

在LiveJournal的鏈路的參數是:(1)通過創建一個單獨的指針變量,並在安全孔引入了一個間接的unneccesary水平指針變量可能被覆蓋。假定以下兩個聲明:

char *p = "This is a test"; 
char s[] = "This is a test"; 

假定這些聲明是在文件範圍內,並因此既ps具有靜態程度。

這裏顯示一切是如何制定了一個假設性的存儲器映射:是

 
        0x00 0x01 0x02 0x03 
     0x00008000: 'T' 'h' 'i' 's' 
     0x00008004: ' ' 'i' 's' ' ' 
     0x00008008: 'a' ' ' 't' 'e' 
     0x0000800C: 's' 't' 0 ... 
     ... 
    p: 0x00010000: 0x00 0x00 0x80 0x00 
    s: 0x00010004: 'T' 'h' 'i' 's' 
     0x00010008: ' ' 'i' 's' ' ' 
     0x0001000C: 'a' ' ' 't' 'e' 
     0x00010010: 's' 't' 0 ... 

在鏈路中提出的論點如下:

  1. 一個額外的變量 - p是一個明顯對象來自它所指向的字符串;它本身不包含字符串值,而s確實包含字符串值;
  2. 更多的攻擊點,該變量是可寫的 - 有可能重新分配p到別處點(也許包含惡意代碼段),而你不能重新分配s
  3. 額外的搬遷 - 不知道這是指什麼(對於我所做的工作,我從來沒有真正擔心機器級別的性能,所以我不熟悉所有的術語);
  4. 獲取字符串地址需要內存加載並訪問字符串本身需要兩次內存加載 - 如果您通過p讀取字符串,首先必須加載0x00010000的內容以獲取字符串地址(0x00008000 ),那麼你必須加載0x00008000的內容來獲取字符串值本身。如果你正在做一個很多,然後用字符數組和切割出一層間接可能導致noticable的性能提升。

總之,你交易,以提高速度和安全性一點記憶。當然,這是假定一個特定的操作環境,並不一定適用。

+1

我必須堅持,因爲我對PMG的評論的回覆一樣,那是你只定義了's',那麼就不必包含目標文件中的文本字符串,所以你*不*買賣內存速度更快(和更安全的訪問),你正在節省內存*和*更快,更安全的訪問。實際上,OP提供的鏈接提倡使用較低內存使用的''樣式定義。我會用證明更新我的答案。 – 2009-11-20 15:22:14

+0

這是一個很好的解釋,除了這個結論「權衡」的評論。 – 2009-11-20 15:23:01

+0

在編寫動態庫的上下文中的「附加重定位」 - 加載庫時,必須根據庫的加載地址更新對靜態對象的所有引用。第一種情況有兩個靜態對象('a'和未命名的字符數組),而第二種情況只有一個。 – caf 2009-11-21 02:54:17

1

在(2)將字符串只存在於一個版本,你是直接通過其地址操縱它。

在(1)是在某個地方在內存中的字符串,然後你把這個地址在另一個位置在內存中,強迫自己從其他位置每次需要它時讀取的地址。實際上,它增加了一個(無用的)間接。

編輯:

正如我在下面的意見和另一個答案說,有是沒有重複(2)。

T.C:

char *p = "This is a test"; 
char s[] = "This is a test"; 

命令gcc -S t.c產生該文件:

.globl _p 
    .cstring 
LC0: 
    .ascii "This is a test\0" 
    .data 
    .align 2 
_p: 
    .long LC0 
.globl _s 
_s: 
    .ascii "This is a test\0" 
    .subsections_via_symbols 

ts.c:

char s[] = "This is a test"; 

命令gcc -S ts.c現在生產的文件:

.globl _s 
    .data 
_s: 
    .ascii "This is a test\0" 
    .subsections_via_symbols 
+0

不。在1)'a'是一個指針,它的內容是一個指向字符串文字的指針; 2)'了'是一個數組,其內容是構成字符串文字字符** **複製爲陣列創建 – pmg 2009-11-20 12:12:49

+0

@pgm然而,在2內存),並因爲它是一個全球性的,我們正在談論在這裏,複製是在編譯時進行的。在「副本」之後,可以從二進制文件中省略現在沒用的字符串文字。你可能想到'char a [] =「...」;'作爲提供全局char數組的初始化的一個方便的語法。 – 2009-11-20 14:11:30

+0

嚴格地說,不是「因爲它是全球性的」,而是「因爲它具有靜態存儲時間」。 – caf 2009-11-21 02:47:46

0

他們是不同的東西,而不是可更換間。

使用1)當你需要一個指針;使用2)當你需要一個數組時;使用3)當你需要一個可調整大小的陣列

3)

#define LITERAL "..." 
char *a = malloc(strlen(LITERAL) + 1); 
if (!a) /* no memory; */ 
strcpy(a, LITERAL);