Go语言禁止普通指针算术以保障内存安全,偏移操作必须经unsafe.Pointer和uintptr转换,且需严格校验对齐、避免悬垂指针与版本依赖风险。

Go 语言不支持指针算术,所谓“指针加减”必须通过 unsafe.Pointer 和 uintptr 组合实现,且极易出错——不是语法不会写,而是稍有不慎就 panic 或读到垃圾值。
为什么 p + 1 直接编译失败?
Go 的普通指针(如 *int)被设计为类型安全、不可运算。编译器禁止任何算术操作,这是内存安全的基石。
- 写
p++、p + 4会报错:invalid operation: p + 4 (mismatched types *int and int) - 这不是限制,而是故意为之:防止 C 风格的越界访问和类型混淆
- 想做偏移,必须先转成
unsafe.Pointer,再转成uintptr才能加减
unsafe.Pointer 不能直接解引用或加减
它只是个“中转站”,不是真正能干活的指针。直接对它操作会编译失败或运行时崩溃。
- 错误写法:
*p(p是unsafe.Pointer)→ 报错:cannot indirect p (variable of type unsafe.Pointer) - 正确流程:先转具体类型指针,再解引用 ——
*(*int)(p) - 想偏移 8 字节?得写:
unsafe.Pointer(uintptr(p) + 8),中间必须经过uintptr - 注意:
uintptr不是指针,GC 完全不认它;一旦脱离单表达式(比如存到变量里),对象可能被回收
字段偏移别手算,用 unsafe.Offsetof 但要验证对齐
结构体字段在内存里的位置不是按顺序紧挨着的,编译器会插 padding 满足对齐要求。
立即学习“go语言免费学习笔记(深入)”;
- 错误假设:
struct{a int32; b int64}中b偏移一定是 4 → 实际通常是 8(因为int64要求 8 字节对齐) - 必须用
unsafe.Offsetof((*T)(nil).Field)获取真实偏移 - 但光有偏移不够:还要检查
unsafe.Alignof和unsafe.Sizeof,确保目标地址满足目标类型的对齐要求,否则在 amd64 上可能 panic:misaligned 64-bit atomic operation - 字段顺序影响布局:把
int64放前面通常比放后面更省空间
切片底层操作最容易踩悬垂指针
用 unsafe.Slice(Go 1.17+)或手动构造 reflect.SliceHeader 改长度/容量,本质是绕过 bounds check,风险极高。
- 常见错误:从空切片或已释放内存构造新 slice → 读写时 crash 或静默数据损坏
- 即使底层数组还在,原 slice 的
len/cap变了,你扩出来的部分可能超出合法范围 - 改
cap尤其危险:如果底层数组正被其他 slice 共享,你的写入会污染别人的数据 - 建议只在明确控制生命周期的场景用(如内存池预分配块),且务必用
runtime.KeepAlive防止提前回收
最常被忽略的点:所有 unsafe 操作都依赖当前 Go 版本和架构的内存布局,它不是 API 合约。哪怕只是升级 minor 版本,struct 字段对齐也可能微调,导致原本跑通的代码突然 panic。


















