英文:
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中,字符串是一个具有两个属性Data
和Len
的结构体。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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论