C 空指针算法
我认为在gcc中,当涉及指针运算时,void*和char*的处理方式是相同的,即void*指向内存中的单个字节,因此下面的代码C 空指针算法,c,pointers,C,Pointers,我认为在gcc中,当涉及指针运算时,void*和char*的处理方式是相同的,即void*指向内存中的单个字节,因此下面的代码 void *p; p = malloc(sizeof(void)); printf("%p %p\n",p,p+1); 确实返回0x984a008 0x984a009。类似地,void**指向一个指针,因此1的增量实际上意味着4字节的增量(在32位操作系统上),即 返回0x984a008 0x984a00c。然而,下面的代码让我感到困惑 void **p, *p1;
void *p;
p = malloc(sizeof(void));
printf("%p %p\n",p,p+1);
确实返回0x984a008 0x984a009
。类似地,void**指向一个指针,因此1的增量实际上意味着4字节的增量(在32位操作系统上),即
返回0x984a008 0x984a00c
。然而,下面的代码让我感到困惑
void **p, *p1;
p = (void **) malloc(sizeof(void *));
p1 = (void **) p;
printf("%p %p\n",p1,p1+1);
因为它再次返回
0x984a008 0x984a009
。这是怎么回事 无效指针不能递增。这是未定义的行为
相关问题:
使用
void*
操作时,增量为1。当您使用void**
时,它是指针的大小
在让您感到困惑的操作中,您的void*
强制转换为void**
将被隐式转换回void*
。就好像你这样做了:
long a, b, c;
c = a + (int) b;
您将
b
强制转换为int
,但随后您希望使用长
进行操作,因此它是强制转换的。暂时忽略无效
指针算术的可能未定义行为
p1
的类型是void*
不能通过为变量指定不同类型的值来更改变量的类型<代码>p1将始终保持无效*
分配给它的任何不同类型的表达式都将隐式转换为void*
(如果不能转换,则给出一个错误)
因此,它本质上与第一个示例相同
编辑:
据我所知,从一个指针类型转换到另一个指针类型实际上没有任何作用,它的主要目的是进行类型检查
指针只是一个内存地址,一个数字,所以从本质上讲,内存看起来像:(post赋值)
p1p2
void*void**您应该使用char*
而不是void*
,因为指向void
的指针上的算术是gcc扩展
char *p1 = /* ... */;
printf("%p %p\n", p1, p1+1);
无论什么点p
,p
上的指针算法都使用char*
类型(而不是char**
)
如果你写:
char *p1 = /* ... */;
printf("%p %p\n", p1, (char**)p1+1);
指针算法使用char**
我知道我在一年后发布了这篇文章,但我偶然发现了这个问题,它引起了我的兴趣
我同意@Dukeling的观点,你不能仅仅通过强制转换来改变变量的类型。但这似乎取决于编译器认为void
是什么。以这个示例程序为例,查看结果输出。请注意,vp
和vp2
之间的唯一区别是sizeof()
部分的malloc()
编译日期:gcc(Debian 4.7.2-5)4.7.2
编译行:gcc-o void\u test void\u test.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
void *vp, *vp2;
printf("sizeof(void) = %d\n", sizeof(void));
printf("sizeof(void *) = %d\n", sizeof(void *));
printf("sizeof(char) = %d\n", sizeof(char));
printf("sizeof(char *) = %d\n\n", sizeof(char *));
vp = (void *) malloc(sizeof(void));
vp2 = (void *) malloc(sizeof(void *));
printf("vp = %p\n", vp);
printf("vp+1 = %p\n", vp+1);
printf("vp2 = %p\n", vp);
printf("vp2+1 = %p\n", vp2+1);
return 0;
}
也许你想输入void**p,**p1代码>而不是无效**p,*p1
?sizeof(void)
为1或至少给出警告,这是无用的。你不能那样做。void
类型表示什么??只有void*
。我的意思是void**p,*p1。我知道这段代码可以编译,但我不知道;我不明白为什么如果p最初被声明为void**,p+1对应于增加4个字节,而如果p1被声明为void*并随后被重铸为void**,那么该算法只为p1+1添加1个字节,为什么,对void**
的转换被忽略了?@Ivan:是的,显然它被忽略了。这是一个身份转换(表达式p
已经有类型void**
)。除了对值类别的某些影响(例如,强制转换的结果是右值)外,标识强制转换将被忽略。OK,但是如果您将所有类型更改为char
pointers,问题仍然存在(尽管在这种情况下,GCC会给您一个警告),这很好,但是编译器为什么要重铸呢?void*
和void**
都在堆栈上占用4个字节,据我所知,所有指针算法都是在编译时完成的。那么,为什么编译器坚持p1被强制转换?请这样想:将void**
强制转换为void*
——任何指针都可以变成void*
。另一方面,用另一种方法来浇铸是不可能的。并非所有指针都是双指针。编译器对您请求的操作执行敏感的操作:这是它唯一能理解的方法。在某些体系结构上,从一种指针类型转换到另一种指针类型确实会改变某些东西。但是,在典型的x86(_64)体系结构上,您可以期望所有指针都具有相同的表示形式,并且强制转换是不可操作的。
char *p1 = /* ... */;
printf("%p %p\n", p1, (char**)p1+1);
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
void *vp, *vp2;
printf("sizeof(void) = %d\n", sizeof(void));
printf("sizeof(void *) = %d\n", sizeof(void *));
printf("sizeof(char) = %d\n", sizeof(char));
printf("sizeof(char *) = %d\n\n", sizeof(char *));
vp = (void *) malloc(sizeof(void));
vp2 = (void *) malloc(sizeof(void *));
printf("vp = %p\n", vp);
printf("vp+1 = %p\n", vp+1);
printf("vp2 = %p\n", vp);
printf("vp2+1 = %p\n", vp2+1);
return 0;
}
$ ./void_test
sizeof(void) = 1
sizeof(void *) = 8
sizeof(char) = 1
sizeof(char *) = 8
vp = 0x1ee3010
vp+1 = 0x1ee3011
vp2 = 0x1ee3010
vp2+1 = 0x1ee3031