2016-10-24 4 views
1

Я пытаюсь вызвать функцию C из Go с помощью cgo, чтобы прочитать сообщение об ошибке. Функция создает сообщение с неизвестной длиной менее 256 байт.Как читать строку из функции C в Go?

Рабочий пример в C:

char message[ERROR_SIZE]; //256 
last_error(message, sizeof(message));   
printf("message: %s\n", message); 

Моя попытка в Go (не работает):

var ptr *C.char 
C.last_error(ptr, ERROR_SIZE) 
var message = C.GoString(ptr) 
fmt.Printf("message: %s\n", message) 

Когда код идти запускается, сообщение пуст. Должна ли версия go to prealocate space для сообщения? Как это сделать?


Обновление после комментария LP для передачи массива. Это работает, но кажется немного неудобным:

var buf [ERROR_SIZE]byte 
var ptr = (*C.char)(unsafe.Pointer(&buf[0])) 
C.last_error(ptr, len(buf)) 
var message = C.GoString(ptr) 
fmt.Printf("message: %s\n", message) 

Есть ли более простой способ?

+1

Не эксперт [тег: go], но функция [tag: c] принимает массив. На стороне [tag: go] вы пропустите простой указатель. – LPs

+1

Спасибо за ваш комментарий @LPs, объявление массива и передача указателя на первый элемент (функция фактически принимает char *). Сообщение напечатано. – Mark

+0

'C.GoString' выделяет пространство по мере необходимости, и оно должно работать в этом случае всякий раз, когда у вас есть строка с нулевым завершением. Если строка не завершена нулем или может содержать нулевые символы, просто рассматривайте ее как байты и используйте 'C.GoBytes'. – JimB

ответ

2

В первом примере вы передаете указатель nil, поэтому выделенной памяти для C.last_error нет, чтобы написать вывод (и, к счастью, он просто ничего не делает).

Вам нужно как-то выделить память, и наиболее простым способом сделать это в Go является использование среза, а не создание массива со статическим размером.

buf := make([]byte, ERROR_SIZE) 
C.last_error((*C.char)(unsafe.Pointer(&buf[0])), len(buf)) 

// While C.GoString will find the terminating null if it's there, 
// there's no reason to copy the string in C, and allocate another slice. 
if i := bytes.IndexByte(buf, 0); i >= 0 { 
    buf = buf[:i] 
} 

fmt.Printf("message: %s\n", buf) 
+0

Блестящий, спасибо @JimB. Оцените подсказку, чтобы избежать копирования. – Mark

 Смежные вопросы

  • Нет связанных вопросов^_^