You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何*(*string)(unsafe.Pointer(&ip))转换bufio.Reader读取的字节数组异常?

问题:unsafe.Pointer转换[]byte到string导致切片元素异常

我有一个存储IP段的文件,内容如下:

1.1.1.0/24
1.1.2.0/24
2.2.1.0/24
2.2.2.0/24

尝试将文件内容读取到字符串切片中,使用*(*string)(unsafe.Pointer(&ip))将[]byte转换为string时出现异常,测试代码如下:

func TestInitIpRangeFromFile(t *testing.T) {
   filepath := "/tmp/test"
   file, err := os.Open(filepath)
   if err != nil {
      t.Errorf("failed to open ip range file:%s, err:%s", filepath, err)
   }
   reader := bufio.NewReader(file)
   ranges := make([]string, 0)
   for {
      ip, _, err := reader.ReadLine()
      if err != nil {
         if err == io.EOF {
            break
         }
         logger.Fatalf("failed to read ip range file, err:%s", err)
      }
      t.Logf("ip:%s", *(*string)(unsafe.Pointer(&ip)))
      ranges = append(ranges, *(*string)(unsafe.Pointer(&ip)))
   }

   t.Logf("%v", ranges)
}

执行结果显示:

task_test.go:71: ip:1.1.1.0/24
    task_test.go:71: ip:1.1.2.0/24
    task_test.go:71: ip:2.2.1.0/24
    task_test.go:71: ip:2.2.2.0/24
    task_test.go:75: [2.2.2.0/24 1.1.2.0/24 2.2.1.0/24 2.2.2.0/24]

可见切片中第一个元素1.1.1.0/24被替换为2.2.2.0/24,但改用string(ip)转换则运行正常。请问该异常的原因是什么?

原因分析
  1. bufio.Reader的缓冲区复用特性
    bufio.Reader内部维护了一块共享缓冲区,每次调用ReadLine()返回的[]byte并非新分配的内存,而是指向这块缓冲区的切片。循环中每次拿到的ip变量,底层指向的是同一块内存区域,只是根据读取内容调整了切片的长度。

  2. unsafe转换是内存引用,无数据复制
    用*(*string)(unsafe.Pointer(&ip))转换[]byte到string,本质是让string直接引用ip指向的共享缓冲区内存,没有复制任何数据。这导致切片中存储的所有string,底层都指向同一个缓冲区。

  3. 后续读取覆盖缓冲区内容
    当循环执行后续的ReadLine()时,bufio.Reader会用新读取的IP段覆盖缓冲区内容。此时,之前存入切片的string因为指向同一块内存,内容会被新数据覆盖。最后一次读取的2.2.2.0/24覆盖了缓冲区,所以切片中第一个元素的内容也变成了这个值。

  4. string(ip)转换的安全性
    使用string(ip)转换时,Go会自动把[]byte中的数据复制到string的独立底层数组中,每个string都拥有专属内存,不会被后续的缓冲区更新影响,因此结果正常。

内容的提问来源于stack exchange,提问作者jx.wtj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 20:35:30