在使用C库的Go语言中,如何正确地将UTF-8编码的字符数组转换为Go字符串?

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

How do I properly convert a UTF-8 encoded char array to a Go string when using a C-library in Go?

问题

我正在尝试在Go语言中使用一个C库。C.PrlFoundVmInfo_GetName函数将一个UTF-8编码的字符串写入name中,长度为nBufSize

以下是正确声明name(和nBufSize)并将name转换为Go语言字符串的方法。上面的代码不按照我期望的方式工作。它打印出:

VM 1024 name: ""

C API文档,摘录

PrlFoundVmInfo_GetName - 参数

PRL_RESULT PrlFoundVmInfo_GetName(
  PRL_HANDLE handle, 
  PRL_STR sName, 
  PRL_UINT32_PTR pnNameBufLength
);
  • handle - 类型为PHT_FOUND_VM_INFO的句柄,用于标识容器。
  • sName - [输出] 用于接收名称的缓冲区的指针。传递一个空指针以确定所需的缓冲区大小。
  • pnNameBufLength - [输入] 用于接收输出数据的缓冲区的大小(以字节为单位)。[输出] 如果缓冲区参数包含空指针或指定的缓冲区大小不够大,则为所需的缓冲区大小。

完整的文档可在C API文档 - PrlFoundVmInfo_GetName中找到。

英文:

I'm trying to use a C library in Go. The C.PrlFoundVmInfo_GetName function writes a UTF-8 encoded string into name with length nBufSize.

<!-- language: lang-go -->

// PRL_CHAR sName[1024];
var sName [1024]C.PRL_CHAR
// PRL_UINT32 nBufSize = sizeof(sName);
var nBufSize C.PRL_UINT32 = C.PRL_UINT32(unsafe.Sizeof(sName))
ret = C.PrlFoundVmInfo_GetName(hFoundVmInfo, (*C.PRL_CHAR)(unsafe.Pointer(&amp;sName)), &amp;nBufSize)
// printf(&quot;VM name: %s\n&quot;, sName);
var gName string = C.GoString((*C.char)(unsafe.Pointer(&amp;sName)))
fmt.Printf(&quot;VM %d name: \&quot;%s\&quot;\n&quot;, nBufSize, gName)

What is the proper way to declare name (and nBufSize) and how do i convert name to a Go string? The above code dosen't work as I expect. It prints:

VM 1024 name: &quot;&quot;
... 

C API Documentation, extract

PrlFoundVmInfo_GetName - Parameters

<!-- language: lang-c -->

PRL_RESULT PrlFoundVmInfo_GetName(
  PRL_HANDLE handle, 
  PRL_STR sName, 
  PRL_UINT32_PTR pnNameBufLength
);
  • handle - A handle of type PHT_FOUND_VM_INFO identifying the container.
  • sName - [out] A pointer to a buffer that receives the name. Pass a null pointer to determine the required buffer size.
  • pnNameBufLength - [in] The size of the buffer used to receive the output data (in bytes). [out] The required buffer size if the buffer parameter contains a null pointer or if the specified buffer size is not large enough.

The full documentation is available at C API Documentation - PrlFoundVmInfo_GetName

答案1

得分: 3

> 命令 cgo
>
> Go 对 C 的引用
>
> 一些特殊的函数通过复制数据来在 Go 和 C 类型之间进行转换。在伪代码中定义如下:
>
> // C 字符串,长度转为 Go 字符串
> func C.GoStringN(*C.char, C.int) string

Go 博客:C?Go?Cgo!

英文:

> Command cgo
>
> Go references to C
>
> A few special functions convert between Go and C types by making
> copies of the data. In pseudo-Go definitions:
>
> // C string, length to Go string
> func C.GoStringN(*C.char, C.int) string

The Go Blog: C? Go? Cgo!

答案2

得分: 0

这是解决方案,创建一个字节数组并使 sName 指向它。在使用后,使用 C.GoStringN 将内容转换为 Go 字符串。

var buf = make([]byte, 1024)
var sName C.PRL_STR = (C.PRL_STR)(unsafe.Pointer(&buf))
var nBufSize C.PRL_UINT32 = 1024
ret = C.PrlFoundVmInfo_GetName(*hFoundVmInfo, sName, &nBufSize)
gName := C.GoStringN((*_Ctype_char)(unsafe.Pointer(sName)), C.int(nBufSize))
fmt.Printf("VM %d name: \"%s\"\n", nBufSize, gName)
英文:

This was the solution, create a byte array and make sName point to it. When it has been used use C.GoStringN to convert the content to a Go string.

<!-- language: lang-go -->

var buf = make([]byte, 1024)
var sName C.PRL_STR = (C.PRL_STR)(unsafe.Pointer(&amp;buf))
var nBufSize C.PRL_UINT32 = 1024
ret = C.PrlFoundVmInfo_GetName(*hFoundVmInfo, sName, &amp;nBufSize)
gName := C.GoStringN((*_Ctype_char)(unsafe.Pointer(sName)), C.int(nBufSize))
fmt.Printf(&quot;VM %d name: \&quot;%s\&quot;\n&quot;, nBufSize, gName)

huangapple
  • 本文由 发表于 2014年2月2日 03:00:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/21502191.html
匿名

发表评论

匿名网友

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

确定