Go语言指针不能相加,因设计上主动禁止指针算术以防止越界、悬空指针和缓冲区溢出;遍历用slice索引或range,仅极少数场景需unsafe.Pointer配合uintptr手动偏移。

Go语言指针不能相加(也不能相减、自增、偏移),这是编译器强制阻止的行为,不是遗漏或待实现功能。
为什么 ptr + 1 会编译失败
Go明确禁止任何指针算术运算,包括ptr + 1、ptr1 - ptr2、ptr++等。尝试运行这类代码会直接报错:
invalid operation: ptr + 1 (mismatched types *int and int)
根本原因不是语法不支持,而是语言设计上主动切断了“通过地址计算访问内存”的路径。这背后有三层硬约束:
- 防止越界:C里
p+1依赖程序员手动算对类型大小,Go不信任这种人工计算 - 避免悬空:GC无法追踪经过算术运算后的指针是否仍指向有效对象
- 杜绝缓冲区溢出漏洞:没有指针算术,就少了一大类可被利用的内存攻击面
想遍历数组或切片?用 slice[i] 或 range
绝大多数你以为需要指针加法的场景,Go都提供了更安全、语义更清晰的替代方式:
立即学习“go语言免费学习笔记(深入)”;
- 访问第i个元素 → 直接写
arr[i]或slice[i](带自动边界检查) - 遍历全部元素 → 用
for i := range slice或for _, v := range slice - 取子区间 → 用切片表达式
slice[2:5],底层已封装起始地址+长度+容量
这些操作由运行时保障安全性,且性能不输手工指针移动——现代Go编译器对slice索引做了大量优化,实际生成的机器码往往和C一样高效。
真要操作内存地址?unsafe.Pointer 是唯一出口
仅在极少数场景下(如解析二进制协议、对接C内存、实现零拷贝序列化),才可能需要模拟指针偏移。这时必须显式进入unsafe包:
arr := [3]int{10, 20, 30}
p := &arr[0]
// 转为 uintptr 才能加减
p2 := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + unsafe.Sizeof(arr[0])))
fmt.Println(*p2) // 20但要注意:
-
uintptr不是指针,GC会忽略它——若原对象已回收,p2就成悬空指针 - 所有对齐、大小、布局都得自己保证,跨平台或升级Go版本可能突然失效
- 一旦出错,panic 位置和原因往往和真实问题点隔很远,调试成本极高
真正难的不是“怎么让指针动起来”,而是判断“是否真的需要绕过类型系统”。99% 的业务代码不需要unsafe;而用了它的那1%,往往要花十倍时间验证内存行为是否始终正确。










