Data modification in GO library not reflecting backing in the C calling C code

The below diagram shows how the communication happens
C <->GO <-> C

I have created a C , shared library and linked it with GO.
GO code is as below, this code interacts with the C code with the exported function CompanyInfo

company.go

package main

/*
 #cgo LDFLAGS: -L. -lcfile
 #include "header.h"
*/
import "C"
import (
	"fmt"
	"unsafe"
)

//export CompanyInfo
func CompanyInfo(company_name *C.char, subsidiary_name *C.char, company_age *C.int) {
	fmt.Println("In company.go!!!")
	fmt.Println("Company_name:", C.GoString(company_name))
	fmt.Println("subsidiary_name:", C.GoString(subsidiary_name))
	fmt.Println("Age:", company_age)
	cmp_name := C.GoString(company_name)
	sub_name := C.GoString(subsidiary_name)
	//C.CFile_print(C.CString(cmp_name), C.CString(sub_name), company_age)
	C.CFile_print((*C.char)(unsafe.Pointer(C.CString(cmp_name))), (*C.char)(unsafe.Pointer(C.CString(sub_name))), company_age)
}

func main() {}

The linked C Code is as follows.

CFile.c

#include <stdio.h>
#include <string.h>
#include "header.h"
//#include "_cgo_export.h"

void CFile_print(char *company_name, char *subsidiary_name, int *company_age) {
	printf("In CFile.c!!!\n");
	printf("company_name:%s\n", company_name);
	printf("subsidiary_name,:%s\n", subsidiary_name);
	printf("company_age:%d\n", *company_age);
	printf("Changing company_name!!!");
	strcpy(company_name, " XXXXX");
	printf("Changed company_name:%s\n", company_name);
	printf("******************************\n");
}

I have compiled this C code as shared library and linked it as follows

gcc -c -Wall -Werror -fpic CFile.c
gcc -shared -o libcfile.so CFile.o

After creating C shared library (libcfile), i have included the same in GO code, and created GO shared library as follows

go build -buildmode=c-shared company.go

After this i tried to call the exported GO function from another C code, as follows

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "toshiba.h"

#define SIZE 50
int main() {
	char *company_name, *subsidiary_name;
	int company_age = 100;
	company_name = malloc(sizeof(char) * SIZE);
	subsidiary_name = malloc(sizeof(char) * SIZE);

	if ( (company_name == NULL) || (subsidiary_name == NULL)) {
		printf("Malloc failed !!!\n");
		exit(EXIT_FAILURE);
	}
	printf("In main.c !!!\n");
	strcpy(company_name, "YYYY");
	strcpy(subsidiary_name, "ZZZZ");
	printf("company_name:%s\n", company_name);
	printf("subsidiary_name,:%s\n", subsidiary_name);
	printf("company_age:%d\n", company_age);
	printf("******************************\n");
	ToshibaInfo(company_name, subsidiary_name, &company_age);
	printf("Changed company_name in main.c:%s\n", company_name);
}

Now here my company name is company_name= YYYY, in library am changing company_name=XXXXX,
after the call to library i am printing the company_name bit it still shows YYYY, why XXXXX is not reflected in main.c ?
What modifications should i do so that XXXXX will get reflected in main.c

Strings in Go are immutable. In your “Go” code (in scare quotes because it’s more C than Go), you

func CompanyInfo(company_name *C.char, subsidiary_name *C.char, company_age *C.int) {
    ...
	cmp_name := C.GoString(company_name)
	sub_name := C.GoString(subsidiary_name)

and C.GoString creates a copy of the underlying C char*. The C.CString that follows in the call to C is yet another copy. This copy might get modified on the C side, but that’s not visible to the caller of CompanyInfo.

If your question is “so, how do I modify a string passed through Go code” the answer is that you don’t, because it would break essential assumptions Go-side. If you want mutable strings you want a []byte and making sure not to copy it along the way.

1 Like