从Golang pkg/net/interface\u windows.go了解ByteptrtToString()
我试图理解将[16]字节转换为字符串的代码:从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
// 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字符串基本上是常量片,所以它将指向与原始字节指针相同的内存地址
这两篇文章将帮助您更好地理解此主题:
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
,或者切片长度错误。