How to use extern c strings in cgo

Viewed 142

I'm trying to use c strings in a c library in a go program, but error occurs:

a.h file:

extern const char *s[];

a.c file:

const char *s[] = {"a", "b", "c"};

I compile the two files to liba.a

main.go file:

package main

// #cgo LDFLAGS: -L${SRCDIR} -la
// #include"a.h"
import "C"
import "fmt"

func main() {
        x := 1
        fmt.Println(x)
        fmt.Println(len(C.s))
        fmt.Println(C.GoString(C.s[x]))
}

then I run the code with command

go run main.go

I got the error:

panic: runtime error: index out of range [0] with length 0

how to fix it? thanks

go version: go version go1.15.7 linux/amd64

1 Answers

Arrays in C are not transparently handled by cgo.

There is what is known as idiomatic Go to map C memory to something Go can naturally manipulate. Here is a working example (main.go):

package main

import (
    "fmt"
    "unsafe"
)

// #cgo LDFLAGS: -L${SRCDIR} -la
// #include "./a.h"
import "C"

func main() {
    x := 1
    fmt.Println(x)
    fmt.Println(len(C.s)) // Note, Go has no idea so it says 0.

    cStr := (*[1 << 30]*C.char)(unsafe.Pointer(&C.s))[x]

    fmt.Println(C.GoString(cStr))
}

The key piece being (*[1 << 30]*C.char)(unsafe.Pointer(&C.s)). What this says is interpret &C.s as a very large constant size array ("large enough for anyone"...), but extract only the element of interest [x] from it.

The use of unsafe.Pointer() should be a warning that looking beyond the end of the actual C array will yield unpredictable results. Indeed, it might crash the program.

Related