在Go中迭代C数组

时间:2016-05-10 13:25:42

标签: c arrays go slice

我正在尝试将绑定写入C库。代码在C:

中调用如下
#include <stdio.h>
#include <stdlib.h>
#include <libvirt/libvirt.h>
#include <string.h>


int main(int argc, char *argv[])
{
    virConnectPtr conn;

    conn = virConnectOpen("qemu:///system");
    if (conn == NULL) {
        fprintf(stderr, "Failed to open connection to qemu:///system\n");
        return 1;
    }


    int nparams = 0;
    virNodeCPUStats* params = malloc(sizeof(virNodeCPUStats) * nparams);
    memset(params, 0, sizeof(virNodeCPUStats) * nparams);

    int cpuNum = VIR_NODE_CPU_STATS_ALL_CPUS;

    if (virNodeGetCPUStats(conn, cpuNum, NULL, &nparams, 0) == 0 &&
        nparams != 0) {
        if ((params = malloc(sizeof(virNodeCPUStats) * nparams)) == NULL)
            goto error;

        memset(params, 0, sizeof(virNodeCPUStats) * nparams);
        if (virNodeGetCPUStats(conn, cpuNum, params, &nparams, 0))
            goto error;
    }


    int err = virNodeGetCPUStats(conn, cpuNum, params, &nparams, 0);
    printf("ret code %d\n", err);
    printf("%d nparams\n", nparams);

    int i = 0;
    for(i = 0; i < nparams; i++){
        printf("%s value\n", params[i].field);
        printf("%llu value\n", params[i].value);        
    }

    fflush(stdout);

error:
    virConnectClose(conn);
    return 0;
}

如您所见,您首先调用virNodeGetCPUStats来获取nparams(它在linux上返回4)然后再使用适当大小的virNodeCPUStats数组调用它,它将填充值并显示如下输出:< / p>

ret code 0
4 nparams
kernel value
991550000000 value
user value
4830840000000 value
idle value
199124620000000 value
iowait value
695120000000 value
PASS

在阅读了libvirt-go和ListAllStorageVolumes的代码后,我尝试了以下实现:

func (c *VirConnection) GetNodeCPUStats(flags C.uint) ([]VirNodeCPUStats, error) {
    var nparams C.int
    var params *C.virNodeCPUStatsPtr
    var cpuNum C.int = -1 // change with cVIR_NODE_CPU_STATS_ALL_CPUS
    var stats []VirNodeCPUStats

    if C.virNodeGetCPUStats(c.ptr, cpuNum, nil, &nparams, 0) == 0 {
        retcode := C.virNodeGetCPUStats(c.ptr, cpuNum, (*C.virNodeCPUStats)(unsafe.Pointer(&params)), &nparams, C.uint(0))
       fmt.Println("D> Retcode: ", retcode) --> outputs 0, okay

    } 

    fmt.Println("D> params: ", params)

    header := reflect.SliceHeader{
        Data: uintptr(unsafe.Pointer(params)),
        Len:  4,
        Cap:  4,
    }

    slice := *(*[]C.virNodeCPUStatsPtr)(unsafe.Pointer(&header))
    for _, ptr := range slice {
        stats = append(stats, VirNodeCPUStats{ptr}) //add for first
    }
    C.free(unsafe.Pointer(params))
    return stats, nil
}

但是,它会出现以下错误:

D> params initial:  <nil>
D> Successful: virNodeGetCPUStats
D> nparams:  4
D> ret code:  0
D> params: (*libvirt._Ctype_virNodeCPUStatsPtr)(0x6c656e72656b)
D> Header Data:  119182900487531
D> before slice
D> before for
unexpected fault address 0x6c656e72656b
fatal error: fault
[signal 0xb code=0x1 addr=0x6c656e72656b pc=0x4c0c04]

goroutine 87 [running]:
runtime.throw(0x613078, 0x5)
    /usr/local/go/src/runtime/panic.go:547 +0x90 fp=0xc820053c80 sp=0xc820053c68
runtime.sigpanic()
    /usr/local/go/src/runtime/sigpanic_unix.go:27 +0x2ab fp=0xc820053cd0 sp=0xc820053c80
github.com/rgbkrk/libvirt-go.(*VirConnection).GetNodeCPUStats(0xc820053ef0, 0x0, 0x0, 0x0, 0x0)
    /home/tugba/go/src/github.com/rgbkrk/libvirt-go/libvirt.go:879 +0xa84 fp=0xc820053ec0 sp=0xc820053cd0
github.com/rgbkrk/libvirt-go.TestGetCPUStats(0xc8200beea0)
    /home/tugba/go/src/github.com/rgbkrk/libvirt-go/libvirt_test.go:833 +0x66 fp=0xc820053f58 sp=0xc820053ec0
testing.tRunner(0xc8200beea0, 0x91acf8)
    /usr/local/go/src/testing/testing.go:473 +0x98 fp=0xc820053f90 sp=0xc820053f58
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:1998 +0x1 fp=0xc820053f98 sp=0xc820053f90
created by testing.RunTests
    /usr/local/go/src/testing/testing.go:582 +0x892

我没有正确切割C数组吗?到底是怎么回事?什么是意外故障,它怎么能在一个地址?这是否意味着我正在使用我不应该的记忆?

0 个答案:

没有答案