2011-10-06 63 views
5

我有以下的测试程序:为什么char *在C中被当作char **处理?

#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

int main(void){ 
    char buf[512]; 
    buf[0]= 0x1; 
    buf[1]= 0x2; 
    char *temp1 = &buf; 
    char *temp2 = buf; 
    char *temp3 = &buf[0]; 
    printf("temp1:%p, temp2:%p, temp3:%p\n",temp1,temp2,temp3); 
    printf("0 = %d, %d, %d\n",temp1[0],temp2[0],temp3[0]); 
    printf("1 = %d, %d, %d\n",temp1[1],temp2[1],temp3[1]); 
    return; 
} 

它编译一个警告:

但是当我运行它,所有的三分球表现是相同的。

./testptr 
temp1:0x7fff3a85f220, temp2:0x7fff3a85f220, temp3:0x7fff3a85f220 
0 = 1, 1, 1 
1 = 2, 2, 2 

我知道buf == &buf[0],但为什么&buf == &buf[0]&buf不应该是char**

+1

'&buf'实际上是一个char(*)[512]'(一个指向512个“char”数组的指针)。他们不完全一样。 –

+0

您在捕获编译器输出和将代码粘贴到问题之间更改了代码。问题现在在第9行。 –

+0

对不起,您刚刚添加了一个新行 – austinmarton

回答

3

所有指针具有相同的行为,因为你宣布他们全部是char*。 C是静态类型的,所以类型绑定到变量而不是值。

既然已经解释了行为部分,我们只需要找出它们为什么具有相同的值(按照%p printf)。那么,这只是GCC实现的一个内存地址指针的工件(偏移和大小,使*与*不同,都由类型系统/编译器在后台处理)。请注意,就像任何发出警告的最可疑的东西一样,这可能是未定义的行为,或者至少是不良做法:)

2

数组不是指针,虽然它们可以以相同的方式使用。你碰巧找到了数组和指针语义不同的一个方面。

+0

当我意外地将'&buf'而不是'buf'作为类型为'void *'的第二个参数传递给[recv](http://linux.die.net/man/2/recv)函数时,我发现了这个。即使我上面的例子没有说明它,这可能会导致问题吗? – austinmarton

+0

@austinmarton:当涉及到C编译器警告时,我更喜欢在偏执狂方面犯错 – hugomg

+0

@missingno:公平的呼叫。在我原来的应用程序中,这个错误是作为一个void指针传递的,所以没有产生警告。 – austinmarton

1

您可以从*&运算符的代数中解出。

  • 我们知道bufbuf阵列的第0个元素的地址

  • 我们知道&buf[0]也是第0个元素

  • 由定义的地址buf[0]相当于*(buf+0)

  • &(*(a))相当于a

所以,&buf[0]变得&(*(buf+0))这是buf

更新

在这里,让我们摊开来作为证据。

  1. &buf[0]鉴于。
  2. &(buf[0])被C优先规则与()的
  3. &((*(buf+0)))因为buf[0] == *(buf+0)
  4. &(*(buf+0))消除多余的括号
  5. buf QED
+3

我同意你的意见('buf ==&buf [0]'),但那不是我所问的('&buf == buf'?)。 – austinmarton

+0

@austinmarton,请按照以下步骤操作:它们证明了,是的,'&buf'等同于'buf'。 –

+1

@Charlie:不,证明表明'&buf [0]'等同于'buf',而不是'buf'等同于'buf',这就是问题所在。 – icktoofay

1

如果您考虑编译器实际生成的代码是什么时它处理一个数组,它变得更加清晰。名称buf引用数组的第一个(第零个)元素的地址(包含字符的连续空间)。如果您在符号表的条目中查找“buf”的对象,则会找到该第一个元素的地址。当你引用buf [0]时,编译器会生成buf的地址,再加上char的大小的零倍。这恰好与buf本身的地址相同。

相关问题