I am trying to understand cgo. I can call C functions from go and the other way also. I tried doing something different and it didn't work.
go code:
// main.go
package main
/*
extern void myfunction(GoSlice s);
*/
import "C"
func main() {
var s [5]byte
C.myfunction(s[:])
}
C code:
// main.c
#include "_cgo_export.h"
#include <stdint.h>
void myfunction(GoSlice s)
{
for (int i = 0; i < s.len; i++)
printf("%hhu ", ((uint8_t *)s.data)[i]);
}
The compilation fails because GoSlice is not defined at the time of the C function declaration in main.go. Also, I can't include _cgo_export.h in main.go to get the definition. Is there any way I can get this working ? Note that I can get the functionality working using C compatible data types. But I want to directly use go data type here.
Related
I have C code in which I am calling golang functions. I am able to do it for primitives data types (int/float etc.) but I want to return some other data structure like array/list/slice.
I could not find any solution on internet.
Looking for help.
Want to return a array/slice/list of string data type.
It would be helpful if you provide additional information, i.e. example code you are currently working on.
As stated from the Cgo documentation page:
Go array types are not supported; use a C pointer
To do so
hello.go
package main
// #include <stdlib.h>
import "C"
import "unsafe"
// StringSlice is a wrapper arround GoStringSlice to make it usable in C.
//export StringSlice
func StringSlice() **C.char {
x := GoStringSlice()
ret := C.malloc(C.size_t(len(x)) * C.size_t(unsafe.Sizeof(uintptr(0))))
// convert to usable format so we are able to fill it with data
pRet := (*[1<<30 - 1]*C.char)(ret)
for i, item := range x {
pRet[i] = C.CString(item)
}
return (**C.char)(ret)
}
func GoStringSlice() []string {
return []string{
"Hello",
"World",
}
}
func main() {}
hello.c
#include <stdio.h>
#include "hello.h"
int main() {
printf("Hello from C!\n");
char **slice = StringSlice();
int numItems = sizeof(slice) / sizeof(char *);
printf("Number of items: %d\n", numItems+1);
printf("String #0: %s\n", *slice);
slice++;
printf("String #1: %s\n", *slice);
return 0;
}
You have to execute go build -buildmode=c-archive hello.go which will generate a hello.h and hello.a.
The hello.a has to be compiled with your C code: gcc -pthread hello.c hello.a -o hello.
package main
/*
#include <inttypes.h>
#pragma pack(1)
typedef struct _sss {
uint64_t some; // ok
uint32_t wow; // ok
uint64_t some2; // not found
uint64_t some3; // not found
uint64_t some4; // not found
uint32_t some5; // ok
} Type;
#pragma pack()
*/
import "C"
import (
"fmt"
)
func main() {
s := C.Type{}
s.some = 10;
s.wow = 10;
s.some2 = 10;
s.some5 = 10;
fmt.Println("Hello, playground")
}
I declared struct named C.Type.
If pragma pack(1) and 64 bits members are used together.
╭─dire#dire-81w4 ~/workspace
╰─go run test.go 2 ↵
# command-line-arguments
./test.go:25:6: s.some2 undefined (type _Ctype_struct__sss has no field or method some2)
Compilation is possible by removing pragma pack(1).
Go 1.15 version is being used. Do you know why?
I found answer about my question.
If the fields of a C struct are aligned such that they can't be represented by a Go struct, then they cannot be accessed directly from cgo. You will have to write functions in C to read and write those fields.
I nowdays am too busy to comment. It's late, but it's answered.
I am trying to use cgo to use Go package in C code. Following is a piece of my code:
func LinearTransformToUInt8(frame []int64, winWidth int, winCenter int) []uint8 {
var transformed []uint8
// my cool code
return transformed
}
However, when calling from C, it says
panic: runtime error: cgo result has Go pointer
I believe the problem is the returned []uint8 is a Go type, which should be replaced by a C type. However, I don't know how to achieve it. Please help!
main.go
package main
import (
"C"
"unsafe"
)
import (
"reflect"
)
func main() {
}
//export phew
func phew() uintptr {
res := make([]uint8, 2)
for i := 0; i < 2; i++ {
res[i] = uint8(i + 1)
}
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&res))
return hdr.Data
}
main.c
#include <stdio.h>
#include <inttypes.h>
#include "libtemp.h"
int main(){
uintptr_t resPtr = phew();
uint8_t *res = (uint8_t*)resPtr;
for (int i = 0; i < 2; i++){
printf("%d\n", res[i]);
}
printf("Exiting gracefully\n");
}
You cannot pass a Go pointer which contains other Go Pointer, slice,string,channel,function, interface, map contain pointers.
So one cannot pass them around, rules to passing around pointers are documented here and go's representation of basic types is documented here.
But some Go contributors were saying, one shouldn't return a Go pointer to C code in the first place.
Is there a way to build a Go + C application that:
From main package X, import packages Y and Z.
Package M exports a go callback F.
Packages X and Y are both built with accompanying C files, both want
to call F from C source code.
Generally speaking I'm trying to figure out how to call a callback from accompanying C files in other modules which are used to build a final application. I coudn't figure out how to achieve this or something similar. I'm also interested in convoluted solutions.
I don't see a way to call a Go function across packages, but all cgo packages are linked into the same binary and can call each other. This means that you can export M.F to a C function in package M and call that C function from packages Y and Z.
m/m.go:
package m
// void F();
import "C"
import "fmt"
//export F
func F() {
fmt.Println("m.f")
}
m/m.h:
void m_f();
m/m.c:
#include <stdio.h>
#include "_cgo_export.h"
#include "m.h"
void m_f() {
printf("m_f\n")
F();
}
y/y.go:
package y
// The LDFLAGS lines below are needed to prevent linker errors
// since not all packages are present while building intermediate
// packages. The darwin build tag is used as a proxy for clang
// versus gcc because there doesn't seem to be a better way
// to detect this.
// #cgo darwin LDFLAGS: -Wl,-undefined -Wl,dynamic_lookup
// #cgo !darwin LDFLAGS: -Wl,-unresolved-symbols=ignore-all
// #include "y.h"
import "C"
import (
"fmt"
_ "m"
)
func Y() {
fmt.Println("y.Y")
C.y()
}
y/y.h:
void y();
y/y.c:
#include <stdio.h>
#include "../m/m.h"
void y() {
printf("y.C.y\n");
m_f();
}
Here is an example, that will accept any go callback (not thread-safe).
b.go:
package b
// typedef void (*cbFunc) ();
// void do_run(cbFunc);
// void goCallback();
import "C"
//export goCallback
func goCallback() {
if goCallbackHolder != nil {
goCallbackHolder()
}
}
var goCallbackHolder func()
func Run(callback func()) {
goCallbackHolder = callback
C.do_run(C.cbFunc(C.goCallback))
}
b.c:
#include "_cgo_export.h"
void do_run(void (*callback)())
{
callback();
}
I couldn't make it to work in a simple fashion IMO.
Given main package X that imports Y and Z, both having to call (from C source code) F declared in package M,
I had to:
Create a small wrapper W1 for F in Y and export it to be called from Y's C source.
Create a small wrapper W2 for F in Z and export it to be called from Z's C source.
In Y CGO CPPFLAGS define -DCALLBACK=W1
In Z CGO CPPFLAGS define -DCALLBACK=W2
From C source code, anywhere, I'm now able to refer to F as CALLBACK (yeah, internally it's all different stuff, which I refer to using a single name at one end to call a single function at the other end).
This is convoluted, but it's working, although configuring such macros and producing little wrappers
is not being ideal. If anyone could detail a simpler procedure I would be glad. Everything
I tried ended up with duplicated symbols or non-visible declarations.
I want to malloc large number of objects in to memory.(about 100 million objects) because the gc of golang is not effective enough,so i need to use c/c++ to malloc memory and use std::vector to hold objects.
this is my code,i want use std container in cgo:
package main
import (
"fmt"
)
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
using namespace std;
void dosome(){
vector<int> ivec; // empty vector
for (vector<int>::size_type ix = 0; ix != 10; ++ix)
ivec[ix] = ix; // disaster: ivec has no elements
}
*/
// #cgo LDFLAGS: -lstdc++
import "C"
//import "fmt"
func main() {
C.dosome()
var input string
fmt.Scanln(&input)
}
and have error message below:
go run stddemo.go
# command-line-arguments
./stddemo.go:13:10: fatal error: 'vector' file not found
#include <vector>
^
1 error generated.
how can i set the include path or is there another idea?
While you can use C++ with CGo, you can't embed that code inside the .go file, since it ultimately gets built with a C compiler.
Instead, place your dosome function in a separate .cpp file in the same directory as the .go file, and declare your function to use C linkage. For example:
extern "C" {
void dosome() {
vector<int> ivec;
...
}
}
If you include a prototype for the function in the CGo comment in the .go file so you can call it from Go.
Since you have multiple files now, you can't use the go run foo.go shorthand any more (since it only compiles a single file). Instead, you will need to use go run package or go build package, where your code is located at $GOPATH/src/package.
Uhh I think your conclusions are a bit too fast. GC cost is driven by two things: The more garbage your program produces, the more the GC will have to run. Second: The more pointers there are to scan, the longer a single GC will take.
That is to say: as long as you put your 100 million things into a go slice and keep them there: the GC won't have to run much, because there's no garbage. And second: if your things don't contain pointers, GC time, should it still occur, will be fine.
So, my question is: do your things have pointers?
if you just want to call someone's golang code this is a quick ram inefficient way:
package main
import "C"
import "fmt"
import "unsafe"
func intArrayFromC (src unsafe.Pointer, sz int) []uint64 {
dest := make([]uint64, sz)
copy(dest, (*(*[1000000000]uint64)(unsafe.Pointer(src)))[:sz:sz])// big number dose not affect ram.
return dest
}
//export doPrint
func doPrint(src unsafe.Pointer, sz int){
var numbers []uint64 = intArrayFromC(src, sz);
for i := 0; i < len(numbers); i++ {
fmt.Printf("%d index: %d\n", numbers[i], i)
}
}
func main() {}
and the c++ code:
#include "print.h"
#include <string.h>
#include <vector>
int main() {
std::vector<GoUint64> numbers{99,44,11,00,2,33,44};
while (1) {
doPrint(numbers.data(), numbers.size());
}
return 0;
}