我有两个结构:
type struct1 struct{
arr [num1]byte
}
type struct2 struct{
b1 [n1]uint64
b2 [n2]uint64
b3 [n3]uint64
}
现在,我有两个指向这些结构的指针:
p1 := new(struct1);
p2 := new(struct2);
在一些计算之后,我想将p2复制到p1的指定部分。类似的东西:
copy(p1.arr[k:], p2);
其中k是正整数。它可以使用memcpy
在C中轻松完成,但我无法在GO中找到一种简单的方法,无需使用任何外部库。有没有人有什么建议?我真的很感激。
答案 0 :(得分:2)
你所说的问题在Go的类型方面没有意义。与C不同,Go强制执行其类型,并且不允许您访问底层字节(不使用不安全)。
对于您的问题,您需要重新设置它,以便按顺序将每个数组从p2复制到p1。为此,您需要单独复制每个:
k += copy(p1.arr[k:], p2.b1)
k += copy(p1.arr[k:], p2.b2)
k += copy(p1.arr[k:], p2.b3)
通过unsafe可以破坏类型安全并直接复制字节。问题是,无法保证它实际上会做你想要的。编译器可能在实际内存布局中将b2放在b1之前,并导致它执行您不想要的操作。这不太可能,但编译人员在追求性能方面做了很多奇怪的事情。 C人喜欢称那些东西"未定义的行为"。在Go中使用不安全实质上会触发UB,我不会推荐它。但是,为了完整起见,以下是Go中的memcopy方式:
p2Slice = (*(*[unsafe.Sizeof(*p2)]byte)(unsafe.Pointer(p2)))[:]
copy(p1.arr[k:], p2Slice)
如果那看起来很难看......那是故意的,因为你不应该这样做!但严肃地说,你可以把我在一行上做的事情分成多行,使其更具可读性。
const s = unsafe.Sizeof(*p2)
p2Arr = *(*[s]byte)(unsafe.Pointer(p2))
copy(p1.arr[k:], p2Arr[:])
答案 1 :(得分:1)
您想绕过Go类型系统,这是不安全的。因此,你应该非常小心。将其实现为一个函数,并使用Go测试包编写测试。检查错误。编写简单易读的代码。不要聪明。
例如,
package main
import (
"fmt"
"unsafe"
)
const num1 = 42
type struct1 struct {
arr [num1]byte
}
const (
n1 = 1
n2 = 2
n3 = 1
)
type struct2 struct {
b1 [n1]uint64
b2 [n2]uint64
b3 [n3]uint64
}
func arrInsert(p1 *struct1, i1 int, p2 *struct2) int {
if p1 == nil || p2 == nil {
return 0
}
if i1 < 0 || i1 >= len(p1.arr) {
return 0
}
s1 := p1.arr[i1:]
s2 := (*[unsafe.Sizeof(*p2)]byte)(unsafe.Pointer(p2))[:]
return copy(s1, s2)
}
func main() {
p1 := new(struct1)
p2 := new(struct2)
for i := range p2.b1 {
p2.b1[i] = uint64(i + 10)
}
for i := range p2.b2 {
p2.b2[i] = uint64(i + 20)
}
for i := range p2.b3 {
p2.b3[i] = uint64(i + 30)
}
n := arrInsert(p1, 1, p2)
fmt.Println(n)
fmt.Println(*p1)
fmt.Println((*[unsafe.Sizeof(*p2)]byte)(unsafe.Pointer(p2))[:])
fmt.Println(*p2)
}
游乐场:https://play.golang.org/p/KA0B0xpFR6l
输出:
32
{[0 10 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 30 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]}
[10 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 21 0 0 0 0 0 0 0 30 0 0 0 0 0 0 0]
{[10] [20 21] [30]}