Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go: passing argv to C function

Tags:

go

argv

cgo

Since Go 1.6 this code:

argc := len(*argv)
c_argc := C.int(argc)

c_argv := make([]*C.char, argc)
for index, value := range *argv {
    c_argv[index] = C.CString(value)
    defer C.free(unsafe.Pointer(c_argv[index]))
}

err := C.MPI_Init(&c_argc, (***C.char)(unsafe.Pointer(&c_argv)))

Doesn not work anymore and fails with runtime error: cgo argument has Go pointer to Go pointer. I have read about allocing the array in C with malloc() and then copying everything but this is very difficult to do (because the argv elements have different lengths and also very unperformant

like image 902
Eddynand Fuchs Avatar asked Jan 05 '23 22:01

Eddynand Fuchs


2 Answers

Here's a minimal example, my C skills are rather rusty so there might be a better way:

package main

/*
#include <stdlib.h>
#include <stdio.h>
static void* allocArgv(int argc) {
    return malloc(sizeof(char *) * argc);
}
static void printArgs(int argc, char** argv) {
    int i;
    for (i = 0; i < argc; i++) {
        printf("%s\n", argv[i]);
    }
}
*/
import "C"

import (
    "os"
    "unsafe"
)

func main() {
    argv := os.Args
    argc := C.int(len(argv))
    c_argv := (*[0xfff]*C.char)(C.allocArgv(argc))
    defer C.free(unsafe.Pointer(c_argv))

    for i, arg := range argv {
        c_argv[i] = C.CString(arg)
        defer C.free(unsafe.Pointer(c_argv[i]))
    }
    C.printArgs(argc, unsafe.Pointer(c_argv))
}

playground

like image 141
OneOfOne Avatar answered Feb 20 '23 19:02

OneOfOne


Can't add comment not enough points on stack-overflow , however when I run with go 1.9 I Have to cast the last line to (**C.char)

C.printArgs(argc, (**C.char)(unsafe.Pointer(c_argv)))
like image 36
Vladimir Venediktov Avatar answered Feb 20 '23 18:02

Vladimir Venediktov