go语言 string数据类型格式

在go语言里面定义字符串如下:
var ss string = "12345"

对于一个熟悉C/C++的程序员来说,马上就会想到这个string是一个什么内容,占多大空间,内存如何分配等,下面我们来分析这个问题。

go语言的string是一种数据类型,这个数据类型占用16字节空间,前8字节是一个指针,指向字符串值的地址,后八个字节是一个整数,标识字符串的长度;注意go语言的字符串内部并不以’\0’作为结尾,而是通过一个长度域来表示字符串的长度。

type mystr struct {
    strbuf uintptr;
    strlen uint64;
}

上述就是string的类型定义。下面我们通过代码来验证这个问题:

package main

import (
    "fmt"
    "unsafe"
//  "reflect"
)

type mystr struct {
    strbuf uintptr;
    strlen uint64;
}

func printmemory(p uintptr, size int) {
    fmt.Printf("[0x%16x:%2d] =", p, size)
    for i := 0; i < size; i++ {
        p1 := unsafe.Pointer(p + uintptr(i))
        p2 := (*byte)(unsafe.Pointer(p1))
        fmt.Printf(" %x", *p2)
    }
    fmt.Printf("\n")
}

func main() {
    var ss string = "12345";

    fmt.Printf("string=%v\n", ss)
    fmt.Printf("length=%v\n", len(ss))
    fmt.Printf("size=%v\n", unsafe.Sizeof(ss))
    fmt.Printf("address=%v\n", &ss)

    ptr := unsafe.Pointer(&ss)
    //value := reflect.ValueOf(&ss)
    //fmt.Println(reflect.TypeOf(value), reflect.ValueOf(value).Kind())
    //ptr1 := value.Pointer()
    ptr1 := uintptr(ptr)
    printmemory(ptr1, 16);

    ptr2 := (* mystr)(ptr)
    fmt.Printf("mystr.strbuf=%x\n", ptr2.strbuf)
    fmt.Printf("mystr.strlen=%v\n", ptr2.strlen)
    printmemory(ptr2.strbuf, len(ss)+1);
}

执行结果如下:

$ go build main.go && ./main 
string=12345
length=5
size=16
address=0xc42000e2c0
[0x      c42000e2c0:16] = f1 70 4a 0 0 0 0 0 5 0 0 0 0 0 0 0
mystr.strbuf=4a70f1
mystr.strlen=5
[0x          4a70f1: 6] = 31 32 33 34 35 31

我们看到string的内存结构,包含一个指向字符串数据的指针,和一个标识字符串长度的整数值;而且字符串的结尾并没有一个’\0’来标识,在上述例子中是一个随机值(0x31)。

关于go语言的指针操作

go语言指针和C/C++指针的唯一差别就是:go语言不允许对指针做算术运算(+、-、++、–)。

但是,Go 提供了一套底层库 reflect 和 unsafe,它们可以把任意一个 go 指针转成 uintptr类型的值,然后再像 C/C++一样对指针做算术运算,最后再还原成 go 类型。所以从这个角度上看,go 指针也是可以和 C/C++ 指针一样使用的,只是会比较绕,这同时也要求使用者自己明白,如果真要把指针这么用,那么请记得后果自负。

下面是一个go语言指针运算的例子:
https://play.golang.org/p/z_GMnh38Z1

    原文作者:CodingCode
    原文地址: https://www.jianshu.com/p/31cb4731ce91
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞