Как правильно преобразовать массив символов в кодировке UTF-8 в строку Go при использовании C-библиотеки в Go?

Я пытаюсь использовать библиотеку C в Go. Функция C.PrlFoundVmInfo_GetName записывает строку в кодировке UTF-8 в name с длиной nBufSize.

// 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(&sName)), &nBufSize)
// printf("VM name: %s\n", sName);
var gName string = C.GoString((*C.char)(unsafe.Pointer(&sName)))
fmt.Printf("VM %d name: \"%s\"\n", nBufSize, gName)

Как правильно объявить namenBufSize) и как преобразовать 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 — [out] Указатель на буфер, который получает имя. Передайте нулевой указатель, чтобы определить требуемый размер буфера.
  • pnNameBufLength — [in] Размер буфера, используемого для получения выходных данных (в байтах). [out] Требуемый размер буфера, если параметр буфера содержит нулевой указатель или указанный размер буфера недостаточно велик.

Полная документация доступна по адресу Документация по C API — PrlFoundVmInfo_GetName


person Rickard von Essen    schedule 01.02.2014    source источник


Ответы (2)


Команда cgo

Ссылки Go на C

Несколько специальных функций преобразуют типы Go и C, создавая копии данных. В определениях псевдо-Go:

// C string, length to Go string
func C.GoStringN(*C.char, C.int) string

Блог Go: C? Идти? Вперед!

person peterSO    schedule 01.02.2014
comment
Я сделал Google перед публикацией, но я не могу понять, как создать буфер для выходного параметра, который должен содержать имя. - person Rickard von Essen; 05.02.2014

Это было решением, создайте массив байтов и укажите на него 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)
person Rickard von Essen    schedule 09.02.2014