我正在尝试手动构建一个指针切片,并使用C.calloc()来分配切片的数组部分。我可以成功完成此操作,但是当我尝试添加使用make()分配的指针时,某些值(指针指向的值)似乎是随机变化的。另一方面,如果我要添加的指针的C.calloc()空间,则该值不会更改。或者,如果我使用make()分配切片,并且添加的指针也使用make()分配,则值不会更改。
我确实注意到使用C.calloc()和make()时指针的内存位置有很大不同,但是我不明白为什么这会导致随机更改内存。我是Go的新手,如果我忽略了一些非常简单的内容,请原谅我。
这是我用于手动分配切片的代码:
type caster struct {
ptr *byte;
len int64;
cap int64;
}
var temp caster;
temp.ptr=(*byte)(C.calloc(C.ulong(size),8));
temp.len=int64(size);
temp.cap=int64(size);
newTable.table=*(*[]*entry)(unsafe.Pointer(&temp));
如果我添加的条目分配如下,这将起作用:
var temp caster;
var e []entry;
temp.ptr=(*byte)(C.calloc(C.ulong(ninserts),8));
temp.len=int64(ninserts);
temp.cap=int64(ninserts);
e=*(*[]entry)(unsafe.Pointer(&temp));
for i:=0;i<ninserts;i++ {
e[i].val=hint64(rand.Int63());
}
for i:=0;i<ninserts;i++ {
ht.insert(&e[i]);
}
尽管按以下方式分配条目的内存会随机更改:
var e []entry = make([]entry, ninserts);
for i:=0;i<ninserts;i++ {
e[i].val=hint64(rand.Int63());
}
for i:=0;i<ninserts;i++ {
ht.insert(&e[i]);
}
除非我按以下方式正常构建切片:
newTable.table = make([]*entry, size);
答案 0 :(得分:2)
我正在尝试手动创建一个指针切片,并使用C.calloc()来分配切片的数组部分。
这是明确禁止的。
Go是一种垃圾回收语言,垃圾回收器需要知道指向Go内存的每个指针的位置。因此,在Go和C之间传递指针受到限制。
在本节中,术语“ Go指针”表示指向Go分配的内存的指针(例如通过使用&运算符或调用预定义的new函数),术语C指针表示“指向C分配的内存(例如由调用C.malloc)。指针是Go指针还是C指针是由内存分配方式决定的动态属性。它与指针的类型无关。
请注意,某些Go类型的值(类型的零值除外)始终包含Go指针。字符串,切片,接口,通道,映射和函数类型都是如此。指针类型可以包含Go指针或C指针。数组和结构类型可能包含也可能不包含Go指针,具体取决于元素类型。下面有关Go指针的所有讨论不仅适用于指针类型,还适用于其他包含Go指针的类型。
上面的黑体字是我的。这意味着您绝不能通过C的分配器分配任何这些类型。
使用不安全的软件包可能会破坏这种强制执行,当然,没有什么可以阻止C代码做任何喜欢的事情。但是,违反这些规则的程序可能会以意外和不可预测的方式失败。
这是您自己的代码:
newTable.table=*(*[]*entry)(unsafe.Pointer(&temp));
违反了规则,但失败了。您已经分配了C内存,现在正尝试以切片的形式像Go内存一样使用它。