4

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

Eddynand Fuchs
  • 344
  • 1
  • 13

2 Answers2

6

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

OneOfOne
  • 95,033
  • 20
  • 184
  • 185
  • 3
    @EddynandFuchs Glad to help, if the tweaks you made made it better optimized, please post a play link here so future readers would benefit too. – OneOfOne Jun 06 '16 at 17:08
  • 1
    I just fitted it to the code given in the question (MPI_Init instead of printArgs) and renamed some variables – Eddynand Fuchs Jun 08 '16 at 19:30
3

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)))