I am trying to a call C function in GO. This works to some extends (for integers). However, there are issues A minimal example is given below
package main
/*
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void my_reverse(char* src, int len, char *dst){
dst = malloc(sizeof(char) * (len + 1));
printf("[c-part] src=%s
", src);
for (int i = 0; i < len; ++i)
{
dst[i] = src[len - 1 - i];
}
dst[len] = 0;
printf("[c-part] dst=%s
", dst);
}
void some_text(char* buffer, unsigned long long int *year){
buffer = malloc(200 * sizeof(char));
sscanf("year 2018d", "%s %16llu", buffer, year);
printf("will return (%s, %16llu)
", buffer, *year);
}
*/
import "C"
import "unsafe"
import "fmt"
func Reverse(a string) (dst string) {
c_src := C.CString(a)
defer C.free(unsafe.Pointer(c_src))
c_len := C.int(len(a))
c_dst := C.CString(dst)
defer C.free(unsafe.Pointer(c_dst))
C.my_reverse(c_src, c_len, c_dst)
return string(*c_dst)
}
func Sometext() (dst string, year int64) {
c_dst := C.CString("")
c_year := C.ulonglong(0)
defer C.free(unsafe.Pointer(c_dst))
C.some_text(c_dst, &c_year)
return string(*c_dst), int64(c_year)
}
func main() {
fmt.Printf("[gopart] dst=%v
", Reverse("Hello World"))
buf, year := Sometext()
fmt.Printf("received (%v, %v)
", buf, year)
}
These are two c-function, which allocate a new buffer in c. However, I get the output
[c-part] src=Hello World
[c-part] dst=dlroW olleH
[gopart] dst=
will return (year, 2018)
received (, 2018)
This means, these strings are available in C.But I can never use these strings in GO afterwards. Does the Go-Garbage collector remove the string before I can use it?
I expect to see
[gopart] dst=dlroW olleH
received (year, 2018)
there as well.
You don't need to handle memory allocation in c if you initialize the strings in Go using C.String
// 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
You can use c.GoString() to convert the C.String back in to go string. Below is a working code snippet of your sample.
package main
/*
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void my_reverse(char* src, char *dst){
printf("[c-part] src=%s
", src);
int n = strlen(src);
for (int i = 0; i < n ; ++i)
{
dst[i] = src[n - 1 - i];
}
dst[n] = 0;
printf("[c-part] dst=%s
", dst);
}
void some_text(char* buffer, unsigned long long int *year){
sscanf("year 2018d", "%s %16llu", buffer, year);
printf("will return (%s, %16llu)
", buffer, *year);
}
*/
import "C"
import "unsafe"
import "fmt"
func Reverse(a string) (dst string) {
c_src := C.CString(a)
defer C.free(unsafe.Pointer(c_src))
c_dst := C.CString(dst)
defer C.free(unsafe.Pointer(c_dst))
C.my_reverse(c_src, c_dst)
return C.GoString(c_dst)
}
func Sometext() (dst string, year int64) {
c_dst := C.CString("")
c_year := C.ulonglong(0)
defer C.free(unsafe.Pointer(c_dst))
C.some_text(c_dst, &c_year)
return C.GoString(c_dst), int64(c_year)
}
func main() {
fmt.Printf("[gopart] dst=%v
", Reverse("Hello World"))
buf, year := Sometext()
fmt.Printf("received (%v, %v)
", buf, year)
}