roger
roger

Reputation: 9893

How to make cgo return array to c?

I am calling golang with c, I want to return a string array and a int array, I do it like this:

package main

import "C"
//export Seg
func Seg(input *C.char, segs *[]*C.char, tags *[]int) (errChars *C.char) {
  count := 10
  segs_ := make([]*C.char, 10, 10)
  for i:=0; i<count; i++ {
    segs_[i] = C.CString("aaaaaa")
  }
  segs = &segs_
  tags_ := make([]int, count)
  for i:=0; i<count; i++ {
    tags_[i] = i
  }
  tags = &tags_
  return
}
func main() {}

Build with

go build -o libacrf.so -buildmode=c-shared clib.go

call it like this:

#include <stdio.h>
#include <stdlib.h>

#include "libacrf.h"

int main(int argc, char *argv[])
{
    GoSlice *segs, *tags;
    char* err;
    err = Seg("hahahhaha", segs, tags);
    if (err != NULL) {
        fprintf(stderr, "error: %s\n", err);
        free(err);
        return 1;
    }
    printf("%llu\n", (*tags).len); // it should be 10, but it is not right now

    return 0;
}

But the problem is that I can not get the real result from golang.

Upvotes: 0

Views: 1865

Answers (2)

JimB
JimB

Reputation: 109318

This doesn't have anything to do with C, you're overwriting copies of the tags and segs pointer values, rather than assigning the new slice values; . Make an example in Go first so see exactly what you're doing. https://play.golang.org/p/EQWRiqVwqm

In order to assign the _tags value to the pointer, the syntax should be

*tags = _tags

Upvotes: 2

Artur Augustyniak
Artur Augustyniak

Reputation: 176

I think it's because you are responsible for memory management for all C-side data. In C GoSlice is just typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; and in your example you pass just uninitialized pointer to GoSlice:

 GoSlice *segs, *tags; //here
 char* err;
 err = Seg("hahahhaha", segs, tags);

So it's just pure luck that you can r/w at this memory location. While Go will not manage your memory chunks from c code it will also not set len field. While all above are just assumptions (i do not know a lot about Go) Some evidence supporting my hypothesis will be this modification:

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

GoInt data[10] = {77, 12, 5, 99, 28, 23, 33,33,33,33};
GoSlice segs_d = {data, 10, 10};
GoInt data2[10] = {77, 12, 5, 99, 28, 23, 33,33,33,33};
GoSlice tags_d = {data2, 10, 10};

GoSlice *segs, *tags;

segs= &segs_d;
tags= &tags_d;

char* err;
err = Seg("hahahhaha", segs, tags);
if (err != NULL) {
    fprintf(stderr, "error: %s\n", err);
    free(err);
    return 1;
}
printf("%llu\n", (*tags).len); // it should be 10, but it is not right now

return 0;
}

Upvotes: 0

Related Questions