Слишком много для комментария, поэтому вот ответ.
Во-первых, оригинальный текст:
Прямым решением является использование C.malloc(4 * C.sizeof(C.double))
для выделения массива double
-s. Обратите внимание, что вы должны обязательно позвонить C.free()
, когда закончите. То же самое относится ко второму массиву одного int
.
Теперь, ваш комментарий к замечанию Маттани, который был немного переформатирован:
спасибо, что дали несколько указателей. Я пробовал с
a1 := [4]C.double{1,1,1,1}
sizeA1 := C.malloc(4 * C.sizeof_double)
cstruct := C.emxArray_real_T{
data: &a1[0],
size: (*C.int)(sizeA1)
}
y := C.sumArray(cstruct)
defer C.free(sizeA1)
но это дало мне то же самое
ответ как и прежде аргумент cgo
имеет указатель Go на указатель Go, когда я
попытался запустить программу
Кажется, вы все еще упускаете важный момент. Когда вы используете cgo
, существует два непересекающихся"представления памяти":
«Память Go» - это все, что выделяется средой выполнения Go для запуска вашего рабочего процесса - от имени этого процесса. Эта память (большую часть времени, за исключением странных уловок) известна GC, которая является частью времени выполнения.
«Память C» - это память, выделенная кодом C - обычно путем вызова libc
s malloc()
/ realloc()
.
А теперь представьте не слишком надуманный сценарий:
- Ваша программа запускается, "сторона" C инициализируется и
порождает собственную нить (или нити) и удерживает на них дескрипторы.
- Ваша сторона Go уже использует несколько потоков для запуска ваших подпрограмм.
- Вы выделяете часть памяти Go в своем коде Go и передаете ее
на сторону С.
- Сторона C передает адрес этой памяти одному или нескольким собственным потокам.
- Ваша программа продолжает пыхтеть, , как и потоки на стороне C - параллельно с вашим кодом Go.
В результате у вас есть достаточно классический сценарий, в котором вы получаете сверхпростую ситуацию для несинхронизированного параллельного доступа к памяти, что является надежным сигналом для аварии на современном многоядерном оборудовании с несколькими сокетами.
Также учтите, что Go значительно более высокоуровневый язык программирования, чем C; Как минимум, он имеет автоматическую сборку мусора и заметит, что в спецификации спецификации Go ничего не указано, как точно должен быть указан GC.
Это означает, что конкретная реализация Go (включая эталонную - в будущем) может свободно разрешать своему ГХ перемещать произвольные объекты в памяти¹, и это означает обновление каждого указателя, указывающего на блок памяти в его первоначальное местоположение, указывающее на то же место в новом месте блока - после того, как оно было перемещено.
Учитывая эти соображения, разработчики Go постулировали, что для того, чтобы cgo
-использовать программы, пригодные для будущего², запрещено передавать на C любые блоки памяти, которые содержат указатели на другие блоки памяти Go.
Впрочем, можно передавать блоки памяти Go, содержащие указатели, в память C.
Возвращаясь к примеру из вашего второго комментария,
Вы по-прежнему выделяете массив 4 double
с a1
в памяти Go.
Затем оператор cstruct := C.emxArray_real_T{...}
снова выделяет экземпляр C.emxArray_real_T
в памяти Go и поэтому после инициализации его поля data
указателем на память Go (&a1[0]
), а затем передает его адрес на стороне C среда выполнения выполняет свои динамические проверки перед тем, как на самом деле вызвать сторону C и вывести из строя вашу программу.
¹ Это типичное поведение для так называемых сборщиков мусора, например,
² То есть вы перекомпилируете свою программу с будущей версией компилятора Go того же «основного» выпуска, и программа продолжает работать без изменений.