指针算术操作的正确方法及内存访问崩溃问题排查
指针算术操作的正确用法与内存访问崩溃问题解析
测试代码
#include<stdio.h> typedef struct cache_malloc { int size; int flags; struct cache_malloc *fwd; struct cache_malloc *bak; } cache_malloc_t; int main() { cache_malloc_t cmp; cache_malloc_t *new = &cmp; new->size = 10; new->flags = 1; printf("======without Arithematic======\n"); printf("(char *)new = %p \n", (((char *)new))); printf("(void *)new = %p \n", (((void *)new))); printf("(int *)new = %p \n", (((int *)new))); printf("======with Arithematic======\n"); printf("(char *)new = %p \n", ((((char *)new)+ 26))); printf("(void *)new = %p \n", ((((void *)new)+ 26))); printf("(int *)new = %p \n", ((((int *)new) + 26))); return 0; }
输出结果
======without Arithematic====== (char *)new = 0xffd65dcc (void *)new = 0xffd65dcc (int *)new = 0xffd65dcc ======with Arithematic====== (char *)new = 0xffd65de6 (void *)new = 0xffd65de6 (int *)new = 0xffd65e34
问题场景
未执行指针算术时,不同类型指针转换后的起始地址完全一致,但执行算术操作后结果差异明显。同时业务代码出现内存访问崩溃:
崩溃代码
cache_malloc_t *cmp; cache_malloc_t *cmp2; cmp2 = (cache_malloc_t *)((int32)cmp + cmp->size + sizeof(cm_cache_malloc_t)); cmp2->size = save; // 此处触发core dump
尝试修改后的代码
// 仍触发core dump cmp2 = (cache_malloc_t *)((int32 *)cmp + cmp->size + sizeof(cm_cache_malloc_t)); // 运行正常 cmp2 = (cache_malloc_t *)((char *)cmp + cmp->size + sizeof(cm_cache_malloc_t));
原理分析
指针算术的核心是按指针指向类型的字节大小进行偏移,而非直接偏移数值本身:
char*类型:char的大小为1字节,(char*)ptr + N实际偏移N个字节,是精准的字节级偏移。int*/int32*类型:int/int32的大小通常为4字节,(int*)ptr + N实际偏移N * 4个字节,偏移量会被放大。void*类型:C标准不允许对void*直接执行算术操作,部分编译器会将其当作char*处理,但属于非标准行为。- 指针转整数算术:将指针转为
int32这类窄整数类型时,64位系统下指针地址会被截断,导致计算出的地址完全错误。
正确的指针算术方法
- 字节级偏移用char*转换:当需要按实际字节数偏移指针时,先将指针转为
char*类型再执行算术,确保偏移量是精准的字节数。 - 避免对非字符类型指针做字节偏移:用
int*等类型做算术时,偏移量会自动乘以类型大小,极易导致地址超出预期范围。 - 禁止指针转窄整数算术:64位系统中指针长度为8字节,用32位整数存储会截断地址,直接引发内存访问错误。
内容的提问来源于stack exchange,提问作者RandomGuy
相关产品推荐
相关产品推荐

