duancai9010 2016-05-10 13:25
浏览 56

在Go中迭代C数组

I am trying to write bindings to a C library. The code is invoked as follows in 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
");
        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
", err);
    printf("%d nparams
", nparams);

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

    fflush(stdout);

error:
    virConnectClose(conn);
    return 0;
}

As you see, you first call virNodeGetCPUStats to get the nparams (it returns 4 on linux) then you call with it again with proper size virNodeCPUStats array, and it will fill the values and an output like the following is shown:

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

Upon reading the code for libvirt-go and ListAllStorageVolumes, I tried the implement the following:

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
}

However, it gives the following error:

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

Am I not slicing the C array properly? What is going on? What is unexpected fault and how can it be at an address? Does that mean I am using a memory I shouldn't be?

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥60 求一个简单的网页(标签-安全|关键词-上传)
    • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
    • ¥15 基于卷积神经网络的声纹识别
    • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
    • ¥100 为什么这个恒流源电路不能恒流?
    • ¥15 有偿求跨组件数据流路径图
    • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
    • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
    • ¥15 一直显示正在等待HID—ISP
    • ¥15 Python turtle 画图