当对切片使用calloc()vs make()时,程序会更改内存值

时间:2019-11-04 02:23:13

标签: go cgo

我正在尝试手动构建一个指针切片,并使用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);

1 个答案:

答案 0 :(得分:2)

  

我正在尝试手动创建一个指针切片,并使用C.calloc()来分配切片的数组部分。

这是明确禁止的。

引用official cgo documentation

  

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内存一样使用它。