前面读书的时候看到有人在讲到了char[]和char*的区别,但是没有细讲。今天看《C陷阱与缺陷》,里面也讲到了这个问题。看了一下还是觉得比较玄乎,想想不如编一个例子然后看看汇编代码,这样一看就应该明了了。
代码非常的简单:
#include <stdio.h>
char filename[] = "/etc/password";
main()
{
char *pathname = NULL;
pathname = filename;
printf("%s",filename);
printf("%s",pathname);
}
$ objdump -dS filename
80483c4: 55 push %ebp
80483c5: 89 e5 mov %esp,%ebp
80483c7: 83 e4 f0 and $0xfffffff0,%esp
80483ca: 83 ec 20 sub $0x20,%esp
char *pathname = NULL;
80483cd: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
80483d4: 00
pathname = filename;
80483d5: c7 44 24 1c 14 a0 04 movl $0x804a014,0x1c(%esp)
80483dc: 08
printf("%s",filename);
80483dd: b8 d0 84 04 08 mov $0x80484d0,%eax
80483e2: c7 44 24 04 14 a0 04 movl $0x804a014,0x4(%esp)
80483e9: 08
80483ea: 89 04 24 mov %eax,(%esp)
80483ed: e8 02 ff ff ff call 80482f4 <printf@plt>
printf("%s",pathname);
80483f2: b8 d0 84 04 08 mov $0x80484d0,%eax
80483f7: 8b 54 24 1c mov 0x1c(%esp),%edx
80483fb: 89 54 24 04 mov %edx,0x4(%esp)
80483ff: 89 04 24 mov %eax,(%esp)
8048402: e8 ed fe ff ff call 80482f4 <printf@plt>
c语言源程序中的filename变量在汇编中被全部替换成为0x80484d0,换句话说在机器代码中filename[]符号并没有一个存储位置,它被替换为一个地址常量。而char* pathname指针变量却要占用自己的存储位置,在本例的代码中就对应于栈空间esp+0x1c位置的数值。现在考虑一下本来的问题,一个c程序由两个源文件组成,其中一个源文件定义了全局变量:char filename[] = "/etc/password";在另一个源文件这样声明了全局变量extern char* filename。问题是这样的程序可以正确运行吗?经过前面的分析,我们可以肯定的回答“不”。因为这种声明方法的内存是单独存在的,而定义中的字符数组的表示filename并没有自己单独的内存空间。编译器会把他们解释为不同的变量。
附带贴一个有意思的bug代码。
#include <stdio.h>
main()
{
int i;
char c;
for (i = 0; i < 5; i++) {
scanf("%d", &c);
printf("%d ", i);
}
printf("\n");
}
今天听了
Bjarne Stroustrup的现场讲座,虽然很多新特性没学,所以没听懂,不过感觉还挺好的。mark一下!