数字和字符的内存储和表示

举报
码乐 发表于 2025/09/09 08:40:19 2025/09/09
【摘要】 1 简介本文简单展示了 Go 里面 数值、字符(本质上也是数值)、变量在内存里的管理方式,以及和字符串/UTF-8 表达方式的差异。以下可以从几个角度拆开来看: 2. 数字在内存里的表达和管理在 Go 里,像 int、float64、byte 等基本数值类型都有固定的内存宽度,例如: int 在 64 位系统通常是 8 字节(64bit) int32 就是 4 字节 floa...

1 简介

本文简单展示了 Go 里面 数值、字符(本质上也是数值)、变量在内存里的管理方式,以及和字符串/UTF-8 表达方式的差异。

以下可以从几个角度拆开来看:

2. 数字在内存里的表达和管理

在 Go 里,像 int、float64、byte 等基本数值类型都有固定的内存宽度,例如:

		int 在 64 位系统通常是 8 字节(64bit)

    int32 就是 4 字节

    float64 就是 8 字节

		byte 等价于 uint8,就是 1 字节

所以 :

  b := 42
  a := 43

编译器会在栈上为 a 和 b 各分配一块固定大小的内存(比如 8 字节),地址可以用 &a 取到。你看到的 fmt.Printf(“%d\n”, &a) 打印出的就是内存地址。

  • 特点:

定长存储:数字的存储大小固定(编译期已知),所以内存地址管理很高效。

连续栈分配:在 main 函数里,这些局部变量一般是按顺序分配在栈上,所以你会看到 &a, &b, &c… 地址是紧挨着的。

值语义:数字变量传参时会复制值,除非你显式传指针(比如 square 函数那一例)。

3. 字符和 UTF-8 在 Go 中的区别

Go 的 string 本质上是 只读的字节切片,底层表示是:

  type string struct {
      data *byte  // 指向底层字节数组
      len  int    // 字符串长度(字节数,不是字符数)
  }

如果是 ASCII 字符(‘a’、‘Z’),其实只占 1 字节。

如果是 中文/emoji,按照 UTF-8 编码,一个字符可能占 3~4 字节。

所以字符串长度 len(“你好”) 是 6,不是 2。

  • 特点:

变长存储:UTF-8 每个字符所需字节不固定。

堆分配:字符串字节数组通常在堆上分配,string 结构体(data 指针和长度)在栈上。

需要解码:遍历字符串要解码 UTF-8,Go 提供了 for range 直接解码成 rune(相当于 int32)。

4. 数值 vs UTF-8 存储效率对比

数值(int、float、byte)

内存大小固定,地址计算简单。

更适合数值计算和密集存储(比如数组 [1000000]int 直接一块连续内存)。

字符串(UTF-8)

存储大小不固定,取决于字符内容。

适合节省内存(英文占 1 字节,中文占 3 字节),但需要额外的指针和长度管理。

访问单个字符需要解码,开销比整数大。

5. 结合 三个例子分析

  b := 42
      a := 43
      c := 44
      d := 255
      e := 256
      f := 355650
      fmt.Println("a - ", a)
      fmt.Println("a's memory address - ", &a, unsafe.Pointer(&a))
      fmt.Printf("%d \n", &a) //整数显示

      fmt.Println("b's memory address - ", b, &b, unsafe.Pointer(&b))
      fmt.Printf("%d \n", &b) //整数显示
      fmt.Println("c's memory address - ", c, &c, unsafe.Pointer(&c))
      fmt.Printf("%d \n", &c) //整数显示
      fmt.Println("d's memory address - ", d, &d, unsafe.Pointer(&d))
      fmt.Printf("%d \n", &d) //整数显示
      fmt.Println("e's memory address - ", e, &e, unsafe.Pointer(&e))
      fmt.Printf("%d \n", &e) //整数显示
      fmt.Println("f's memory address - ", f, &f, unsafe.Pointer(&f))
      fmt.Printf("%d \n", &f) //整数显示

返回指针

    func square(x int) *int {
        y := x * x
        return &y
    }

这里 y 是局部变量,按理说函数结束后应该销毁。但 Go 编译器会做 逃逸分析,发现 y 的地址被返回了,所以会把 y 分配到堆上(而不是栈上),保证外部还能用。

  • 这也说明 Go 的内存管理不是一成不变的,会根据编译器分析结果决定分配在栈还是堆。

6 小结

数字类型(int/float/byte):定长存储,地址连续,访问速度快,内存管理简单 → 比 UTF-8 更高效。

字符串/UTF-8:变长存储,需要额外的解码和指针管理,更灵活,但在性能上不如数值固定内存表示。

  • 因此:

涉及大量计算/固定大小数据结构 → 数字存储更高效。

涉及文本/多语言 → UTF-8 更节省空间,但有解码成本。

【版权声明】本文为华为云社区用户翻译文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容, 举报邮箱:cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。