如何将Go语言中的字符串类型转换为C绑定类型?

huangapple go评论83阅读模式
英文:

How convert string type from Go to C binding?

问题

我有一个C结构体:

struct sanlk_lockspace {
   char name[48];
}

和Go代码:

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

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

结果是,我看到错误信息:

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

如何正确转换字符串类型?

英文:

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? ?

答案1

得分: 3

简而言之,它不起作用是因为[48]_Ctype_char与*_Ctype_char是非常不同的结构。

在Go语言中,数组与大多数其他语言有很大的区别。在Go中,数组更像是具有数值属性标识符的结构体。在C中,数组是指向特定类型的指针,但开发人员知道在第0个元素之后的连续内存中还有该类型的其他实例。在Go中,字符串是一个具有两个属性DataLen的结构体。Data属性更像是C中的数组或字符串。Len属性是单位类型的连续实例的数量。

你遇到的问题是一个包含48个字段的结构体,所有字段都是c::char类型,无法使用指向c::char实例的指针进行赋值。开发人员知道存在47个与该单个实例连续的分配,但Go编译器对此并不确信。

你可以进行的最简单的转换是声明一个特定类型的结构体,具有{Data *_Ctype_char; Len uintptr},并将Data作为字面结果进行赋值,Len是在遇到_Ctype_char(0)之前可以读取的_Ctype_char值的实例数。

要将其转换为字符串,你需要将单字节的_Ctype_Char转换为多字节的Unicode字符,对于该序列的每个元素,Go类型为glyph

当你拥有一个具有指向glyph的指针和一个uintptr大小的数字的Go结构体实例时,它可以转换为Go类型的字符串。反过来,将每个连续的glyph转换回其对应的uint8,如果存在的话,可以选择实现一些无损转换的策略,并用uint8(0)截断,如果原始值未被保留。这个现在编译器没有记录大小的uint8与_Ctype_char兼容,并且可以写回C类型的字符串。

英文:

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.

huangapple
  • 本文由 发表于 2021年12月14日 23:16:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/70351247.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定