C语言适配

更新于: 2018.08.20

调用C编写的动态库

设动态库名为libtest.so, 在/zzq/lib/下. 暴露以下接口:

int CreateTester(const char* path, const char* binpath, void** handle);
int Test(void* handle, const char* path, int ids[], char **result, size_t *len);
const char* GetErrorMessage(int err);
int DeleteTester(void* handle);

适配代码如下, 注意对C数组, 指针, 指针的指针, void**等元素的适配:

package demo

/*
#cgo LDFLAGS: -L/zzq/lib -ltest -ldl

#include <stdlib.h>

int CreateTester(const char* path, const char* binpath, void** handle);
int Test(void* handle, const char* path, int ids[], char **result, size_t *len);
const char* GetErrorMessage(int err);
int DeleteTester(void* handle);
*/
import "C"
import (
    "fmt"
    "unsafe"
)

type Tester struct {
    handle unsafe.Pointer
}

const (
    // TEST_ERROR_SUCCESS 表示成功的错误码
    TEST_ERROR_SUCCESS int = 0
)

// GetError 返回错误码对应的错误消息字符串
func GetError(err int) string {
    c := C.GetErrorMessage(C.int(err))
    return C.GoString(c)
}

// Create 创建实例
func Create(path string, binpath string) (*Tester, error) {
    if path == "" || binpath == "" {
        return nil, fmt.Errorf("tester: invalid argument")
    }

    var p unsafe.Pointer
    c1 := C.CString(path)
    c2 := C.CString(binpath)
    defer C.free(unsafe.Pointer(c1))
    defer C.free(unsafe.Pointer(c2))
    ret := C.CreateTester(c1, c2, &p)
    if int(ret) != TEST_ERROR_SUCCESS {
        return nil, fmt.Errorf("tester: create failed: %s", GetError(int(ret)))
    }

    t := new(Tester)
    t.handle = p
    return t, nil
}

// Destroy 销毁实例
func (t *Tester) Destroy() error {
    if t.handle == nil {
        return nil
    }
    C.DeleteTester(t.handle)
    return nil
}

//  处理文件
func (t *Tester) Test(path string, ids []int) (string, error) {
    if t.handle == nil {
        return "", fmt.Errorf("tester: invalid handle")
    }
    c := C.CString(path)
    defer C.free(unsafe.Pointer(c))
    var res *C.char = nil
    var l C.size_t
    ret := C.Test(t.handle, c, (*C.int)(unsafe.Pointer(&ids[0])), &res, &l)
    if int(ret) != TEST_ERROR_SUCCESS {
        if res != nil {
            C.free(unsafe.Pointer(res))
        }
        return "", fmt.Errorf("tester: test failed: %s", GetError(int(ret)))
    }

    if res != nil {
        s := C.GoString(res)
        C.free(unsafe.Pointer(res))
        return s, nil
    }

    return "", fmt.Errorf("tester: test failed, unknown error")
}