0

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.

2 Answers 2

2

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
Sign up to request clarification or add additional context in comments.

Comments

0

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;
}

2 Comments

so what about this pure c question?stackoverflow.com/questions/46664685/…
Well, if I understood question well, most basic way. First you must malloc memory for array of N char pointers: char **str_arr = malloc(N * sizeof(char *)); then alloc for each string (at size M max +1 for null terminator): int i; for (i = 0; i < N; ++i) { str_arr[i] = (char *)malloc(M+1); } I would do this outside my function that operates on allocated memory chunk and pass initialized pointer to this function (it looks clearer in terms of who is responsible for freeing this memory - in this case caller).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.