Передача строки из функции на Go в код на C без выделения памяти (часть 2)
В прошлой статье мы обсуждали возможность передачи строки без выделения памяти. При попытке использовать этот метод в реальных проектах выяснилось, что есть случаи, когда метод неприменим. Все работает отлично, если объект string был сконструирован из статической строковой константы или конкатенацией констант. Если же string представляет собой результат объединения других объектов, при выполнении программы произойдет исключение:
mystr := "test string" C.Test(unsafe.Pointer(&mystr)) // работает
mystr1 := "test " + "string" C.Test(unsafe.Pointer(&mystr1)) // работает stradd := "string" mystr2 := "test " + stradd // Op3 C.Test(unsafe.Pointer(&mystr2)) // не работает
При выполнении программы на экран выводится:
panic: runtime error: cgo argument has Go pointer to Go pointer goroutine 1 [running]: received: test string received: test string panic(0x464780, 0xc04204a080) C:/Go/src/runtime/panic.go:500 +0x1af main._cgoCheckPointer0(0xc04204a050, 0xc04204a070, 0x1, 0x1, 0xc04204a06b) _/c_/examples/gostring/gostring/_obj/_cgo_gotypes.go:35 +0x60 main.main() c:/examples/gostring/gostring/gostring.go:20 +0x2ae
Не понятно, где cgoCheckPointer0 обнаруживает указатель на указатель. Возможно, это будет исправлено в следующих версиях. Возможно и другое — что метод, предложенный ниже, о том, как «обмануть» cgoCheckPointer0, перестанет работать.
Решение
Итак, для того, чтобы не допустить исключения, пытаемся избежать проверки как таковой, преобразовав указатель в целое число:
package main /* typedef unsigned long long ULongLong; extern void Test1(ULongLong l); */ import "C" import "unsafe" func main() { v1 := "test " v2 := "test 2" str := v1 + v2 t := uintptr(unsafe.Pointer(&str)) C.Test1(C.ULongLong(t)) }
Код функции на C в данном случае:
#include <_cgo_export.h> #include <string.h> #include <stdio.h> typedef unsigned long long ULongLong; void Test1(ULongLong v) { GoString* gs = (GoString*)v; char buf[64]; int n = gs->n < sizeof(buf) - 1 ? gs->n : sizeof(buf) - 1; strncpy(buf, gs->p, n); buf[n] = '\0'; printf("received: %s\n", buf); }
Заключение
При запуске программа работает. Это свидетельствует о том, что структура данных, в которой хранится строка str, ничем не отличается от того, что используется для хранения статических строковых констант и их конкатенации — это все тот же GoString, о котором мы говорили в части 1 («Передача строки без выделения памяти из функции на Go в код на C (часть 1)»).
received: test test 2
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.
Нет комментариев