Bdfy
Bdfy

Reputation: 24719

How convert string type from Go to C binding?

I have C struct:

struct sanlk_lockspace {
   char name[48];
}

and go-code:

/*
#include ....
*/
import "C"

func main() {
    ls := C.struct_sanlk_lockspace{name: C.CString("lockspace_11")}
}

As result, I see error:

   cannot use _Cfunc_CString("lockspace_11") (type *_Ctype_char) 
   as type [48]_Ctype_char in field value

How to convert the string type correctly? ?

Upvotes: 1

Views: 225

Answers (1)

Sam Hughes
Sam Hughes

Reputation: 785

In short, it's not working because [48]_Ctype_char is a very different structure than *_Ctype_char.

In Go, an array is quite different from most other languages. An array in Go is more like a struct with numeric property identifiers. In C, an array is a pointer to a specific type, but where it is known to the developer that additional instances of that type are in contiguous memory after the 0th element. In Go, a string is a struct with two attributes, Data and Len. The Data attribute is more like what C knows as an array or string. The Len attribute is the number of contiguous instances of the unit-type.

The trouble you're having is that a struct of 48 fields, all c::char, is not assignable with a pointer to an instance of c::char. The fact that 47 allocations exist contiguous with that single instance is something you as the developer know, but it is a fact concerning which the Go compiler is quite unconvinced.

The simplest cast you could do would be to declare a specific type as a struct with {Data *_Ctype_char; Len uintptr}, and assign the value with Data as the literal result, and Len is the number of instances of _Ctype_char values that can be read before encountering _Ctype_char(0).

To convert that to a string, you would have to convert the single-byte _Ctype_Char to a multi-byte unicode character, of Go-type glyph for each element of that sequence.

At the point that you have a Go instance of a struct with a pointer to glyph and a uintptr sized number, it can be converted to a Go-type String. The reverse would be to convert each contiguous glyph back to its uint8 correlative, if one exists, optionally implementing some strategy to losslessly convert, and cap it with a uint8(0) if the original was not preserved. That *uint8, which the compiler now has no record as to size, is compatible with *_Ctype_char, and can be written back to a C-type string.

Upvotes: 3

Related Questions