2

I'm trying to call Go from c++. My code operates on maps, and I can't seem to make maps work with cgo.

main.go:

package main

import (
    "C"
    "fmt"
)

func main() {}

//export PrintMap
func PrintMap(m map[string]string) {
    fmt.Println(m)
}

Which "compiles" to main.h:

typedef void *GoMap;

extern void PrintMap(GoMap p0);

How can I successfully create a GoMap in my c++ code and pass it to the go code?

speller
  • 1,641
  • 2
  • 20
  • 27
  • I've tried passing an std::map but obviously it didn't work. – speller Feb 17 '20 at 16:38
  • Also, I can't even create a map in go and pass it to the c++ code to store. Go runtime panics if you pass a Go map to C code. `panic: runtime error: cgo result has Go pointer` – speller Feb 17 '20 at 16:39
  • A workaround can be to convert Go map to string using `json.Marshal()`, pass it as a string and have Go function convert it back to Go map using `json.Unmarshal()`. – Meet Sinojia Mar 19 '20 at 21:19

1 Answers1

6

You can't. In fact, you can't really do anything with this type with cgo due to the pointer-passing rules that allow cgo to work safely with Go's concurrency and garbage collector. Maps are on the list of types that "always include Go pointers", and therefore maps can't be passed as arguments to C functions, returned from Go functions that are called by C code, or stored by C.

It's hard to give a recommendation on what you should do without seeing more of what you're trying to accomplish, but the usual workaround for this is to have the Go code hold objects in a map, and pass the C code a key from that map (as e.g. a C string or int, which can be passed or stored freely) as a handle to the object contained within. C then does all of its interaction with the objects through Go functions, which can use the key to find the correct value in the map. A slice would work too.

hobbs
  • 223,387
  • 19
  • 210
  • 288
  • Thanks for the answer. I wonder why would they typedef the GoMap if it can't be passed to go, nor be returned from it. What I'm actually trying to do is to pass a map of http headers, keys and values to go, and to process them there. I guess I have no choice but to pass them as 2 slices of strings, one for keys and one for values. – speller Feb 17 '20 at 19:05
  • @speller before Go 1.5, it would have been usable as an opaque type in C, with some restrictions, so I suppose the code for mapping it was written before then, and just never removed. I don't see the use of it today. – hobbs Feb 17 '20 at 22:59