Here is the gist for showing how to send string from c to go without a copy, for sending an float32 array from c to go without copy, please see here
Below is the documentation for converting between a c string and a go string:
// From https://golang.org/cmd/cgo/
// A few special functions convert between Go and C types by making copies of the data.
// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CString(string) *C.char
// Go []byte slice to C array
// The C array is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CBytes([]byte) unsafe.Pointer
// C string to Go string
func C.GoString(*C.char) string
// C data with explicit length to Go string
func C.GoStringN(*C.char, C.int) string
// C data with explicit length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
According to
A few special functions convert between Go and C types by making copies of the data.
we need to avoid calling C.GoString
when converting c string to go string if we want to save a copy.
Here is the comparison code:
foo.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "foo.h"
int main() {
char buf[10];
GoString go_str;
for (int i = 0; i < 10; i++) {
buf[i] = 'a';
}
buf[9] = 0;
go_str.p = buf;
go_str.n = 10;
char *r = bar(go_str, buf);
printf("return: %s\n", r);
free(r);
sleep(3);
for (int i = 0; i < 10; i++) {
buf[i] = 'b';
}
buf[9] = 0;
sleep(100000000);
return 0;
}
foo.go:
package main
import (
"C"
"fmt"
"time"
)
//export bar
func bar(a string, b *C.char) *C.char {
c := a
d := C.GoString(b)
go func() {
for {
time.Sleep(time.Second)
fmt.Println("a:", a)
fmt.Println("b:", C.GoString(b))
fmt.Println("c:", c)
fmt.Println("d:", d)
}
}()
return C.CString("hello from go")
}
func main() {}
Command:
go build -buildmode=c-archive foo.go
gcc foo.c foo.a -o 123 && ./123
Output:
a: aaaaaaaaa
b: aaaaaaaaa
c: aaaaaaaaa
d: aaaaaaaaa
a: aaaaaaaaa
b: aaaaaaaaa
c: aaaaaaaaa
d: aaaaaaaaa
a: bbbbbbbbb
b: bbbbbbbbb
c: bbbbbbbbb
d: aaaaaaaaa
a: bbbbbbbbb
b: bbbbbbbbb
c: bbbbbbbbb
d: aaaaaaaaa
a: bbbbbbbbb
b: bbbbbbbbb
c: bbbbbbbbb
d: aaaaaaaaa
You will see that row "d:" never changed to "bbbbbbbbb" since C.GoString made a copy when converting c string to go string.