C语言中void**类型指针自增步长为8的原因及非char*类型转换的解决方法咨询
嘿,这个问题其实是C语言指针类型系统的核心知识点,我给你掰扯清楚~
为什么
(void**)a + 1的步长是8? 首先得记住一个C语言的铁规则:指针的算术运算(加减)步长完全由指针指向的目标类型大小决定。
你这里的void**是一个「指向void*的指针」——换句话说,这个指针认为自己指向的是一个个void*类型的变量。而在64位操作系统中,所有指针类型(包括void*)的大小都是8字节(因为要存储64位的内存地址)。所以当你对void**类型的指针执行+1时,编译器会自动帮你把指针的值加上sizeof(void*),也就是8字节,这就解释了为什么输出的地址从1516c0变成了1516c8。
你代码里的a是void**类型,a+1的本质是让指针跳到下一个void*元素的起始位置,步长自然就是8字节啦。
不想用
(char*)类型转换,怎么调整指针步长? 如果不想依赖char*(毕竟char*虽然是C标准里唯一保证步长为1的类型,但有时候用起来不够直观),有两个靠谱的方案:
方案一:用uintptr_t做字节级偏移(通用方法)
uintptr_t是C标准库<stdint.h>中定义的类型,专门用来把指针转换成整数进行算术运算,是跨平台安全的做法。如果你想让指针移动任意字节数,比如1字节,可以这么写:
#include <stdint.h> #include <stdio.h> #include <stdlib.h> int main() { void** a = calloc(4,4); // 把指针转成uintptr_t,加1字节后再转回去 void** new_a = (void**)((uintptr_t)a + 1); printf("%x,%x\n", (unsigned int)a, (unsigned int)new_a); free(a); return 0; }
这样就能精准控制指针的字节偏移,完全不需要char*。
方案二:用uint8_t*直接指向内存(字节级操作更清晰)
如果你本来就是想按字节来操作calloc分配的内存,不如直接用uint8_t*来声明指针——uint8_t是1字节的无符号整数,定义在<stdint.h>里,语义上更明确表示「我要操作单个字节」:
#include <stdint.h> #include <stdio.h> #include <stdlib.h> int main() { uint8_t* a = calloc(4,4); printf("%x,%x\n", (unsigned int)a, (unsigned int)(a+1)); // 步长就是1字节 free(a); return 0; }
这个方案比char*更直观,因为uint8_t明确是字节类型,不会有char可能带符号的歧义。
内容的提问来源于stack exchange,提问作者GuoHaodong
相关产品推荐
相关产品推荐

