2009-11-20 80 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);