Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Golang pkg/net/interface\u windows.go了解ByteptrtToString()_String_Pointers_Go_Byte_Slice - Fatal编程技术网

从Golang pkg/net/interface\u windows.go了解ByteptrtToString()

从Golang pkg/net/interface\u windows.go了解ByteptrtToString(),string,pointers,go,byte,slice,String,Pointers,Go,Byte,Slice,我试图理解将[16]字节转换为字符串的代码: // From: https://code.google.com/p/go/source/browse/src/pkg/net/interface_windows.go func bytePtrToString(p *uint8) string { a := (*[10000]uint8)(unsafe.Pointer(p)) i := 0 for a[i] != 0 { i++ } retur

我试图理解将[16]字节转换为字符串的代码:

// From: https://code.google.com/p/go/source/browse/src/pkg/net/interface_windows.go
func bytePtrToString(p *uint8) string {
    a := (*[10000]uint8)(unsafe.Pointer(p))
    i := 0
    for a[i] != 0 {
        i++
    }
    return string(a[:i])
}

// Type of ipl.IpAddress.String is [16]byte
str := bytePtrToString(&ipl.IpAddress.String[0])
我是说,指针魔术的原因是什么?难道不能简单地写如下吗

func toString(p []byte) string {
    for i, b := range p {
        if b == 0 {
            return string(p[:i])
        }
    }
    return string(p)
}

// Type of ipl.IpAddress.String is [16]byte
str := toString(ipl.IpAddress.String[:])

不,它不能像你建议的那样写。 您忘记了[]字节不是字节数组。它的字节片。 内存片就是一种结构,它有指向缓冲区的指针(字节数组,它将保存数据)和一些关于数组大小的信息

a := (*[10000]uint8)(unsafe.Pointer(p))    
此代码将字节指针转换为字节数组。 在go字节数组中——它只是字节,就像在C中一样。仅此而已。 因此,如果您要声明字节数组:

var buffer [256]byte   
Go将精确分配256个字节,数组甚至没有长度。数组的长度是其类型的一部分,只有编译器才有关于数组长度的信息。 为什么我们可以将字节指针转换为数组。基本上是一样的

i := 0
for a[i] != 0 {
   i++
}
这里我们只找到以null结尾的字符串的结尾

return string(a[:i])   
这里我们使用切片操作来创建字符串。In-Go字符串基本上是常量片,所以它将指向与原始字节指针相同的内存地址

这两篇文章将帮助您更好地理解此主题:


该模块似乎不执行Windows系统调用,其返回值包括“C字符串”,即C
char*
s,指向没有显式长度的字符串。
bytePtrToString
代码看起来是一种合理的方法,可以将其中一个(长度高达10000)转换为Go字符串。是的,我看到了bytePtrToString()试图实现的目标。。。我只是不明白为什么它使用指针而不是像我上面所画的普通切片(甚至是普通数组)。我怀疑模块中至少有一个Windows系统调用实际上没有返回正确的
len
的字节切片,因此func必须组成一个大长度并查找
\0
。可能是在
IpAddress.String
的情况下不需要它,因为长度是有界的,但对于某些其他返回值,它是有界的。我不在窗户上,所以我很难进一步挖掘;抱歉,我的话没有定论。如果你想确定的话,您可以将
net/interface
代码复制到
mynetinterface
包中,并在该文件中散布
fmt.Println
s,以查看Windows API返回的结构是否有任何裸
*字节或伪
len
s为0或1的片段,或其他可以解释需要
不安全
体操。你注意到调用str:=toString(ipl.IpAddress.String[:])正在将完整的[16]字节数组分割成一个16字节的片吗?为什么不行?同意埃弗顿的说法。为了证明模块中的
不安全
技巧的合理性,我需要看到长度未知的源字符串(例如,某些结构中的裸
*字节
)或长度过短(例如,
len=1
,但字符串实际上是100字节)。@Everton,由于指针魔术所涉及的API调用假定返回了指向某个易失性内存位置的指针,Go端必须复制该内存,这就是将
[]字节
转换为
字符串
的类型转换所做的(Go中极少数类型转换隐藏了
O(n)
成本的地方之一)。@everton,您感到困惑的切片技巧已被记录在案——请参阅“将C数组转换为Go切片”一节。@kostix,我认为令人困惑的是,调用代码中已经有一个合理的切片,您似乎可以使用该切片来转换为字符串(以及它所暗示的副本),而不需要
不安全的
技巧。我不得不怀疑
不安全的
技巧是否是残留的,或者是包中的其他代码需要的,如果API未经处理返回
*uint8
,或者切片长度错误。