arrays - Access Go's array of arrays from C
问题描述
Clarification: There does not seem to be a documented example of sending a GO map to a C function as a multidimentional array. This question is intended to find a common solution for anyone sending a collection of data from GO to C.
Question: I have a map[string]string in Go, I'm looking to iterate over this key/value pair in C++.
In GO I have the following to create a multidimensional array
var argv = make([][]*C.char, len(keypairs))
count := 0
for key, val := range keypairs {
var argv2 = make([]*C.char, 2)
csKey := C.CString(key)
csVal := C.CString(val)
argv2[0] = csKey
argv2[1] = csVal
argv[count] = argv2
count++
C.free(unsafe.Pointer(csKey))
C.free(unsafe.Pointer(csVal))
}
C.writeKeyValuePairs(&argv[0])
Then in C++ I have:
bool writeKeyValuePairs(char * pairs[][2]) {
...
}
The result is:
cannot use _cgo1 (type *[]*_Ctype_char) as type *[2]*_Ctype_char in argument
Update to @kostix: Here's where it's at now:
var argv = make([][2]*C.char, len(tags))
i := 0
for key, val := range tags {
var argv2 = new([2]*C.char)
argv2[0], argv2[1] = C.CString(key), C.CString(val)
argv[i] = argv2
i++
}
C.writeKeyValuePairs(&argv[0])
The error being:
Cannot use 'argv2' (type *[2]*C.char) as type [2]*C.char
解决方案
在 Go 中,[]T
并不是你想象的那样:它不是一个数组,而是一个切片。
切片是struct
三个字段中的一个:length int
和capacity int
指向底层(支持)数组的第一个元素的指针。
相反,在 C 和 C++ 中,a直接T[]
是指向内存块的指针(迭代恰好在字节块中完成)。sizeof(T)
因此你char *pairs[][2]
是
- 指向两个类型元素的内存块的指针
char*[]
, - 其中每个元素是指向另一个类型为未知数量元素的数组的指针
char*
。
…而您的 Go[][]*C.char
是切片的切片(即struct
-typed 切片标头,而不是指针)。
你可能需要这样的东西:
var argv = make([][2]*C.char, len(keypairs))
i := 0
for key, val := range keypairs {
var argv2 = new([2]*C.char)
argv2[0], argv2[1] := C.CString(key), C.CString(val)
argv[i] = argv2
i++
}
C.writeKeyValuePairs(&argv[0])
这里我们分配一个数组切片(长度为 2)。在调用 C 端时,您正确获取了封闭数组的第一个元素的地址,因此在顶层有一个切片就可以了。
这段代码的问题是您没有将数据的长度传递argv
给writeKeyValuePairs
,也没有在该数组的末尾使用哨兵值,但我希望您刚刚从示例中省略了这一点。
我也无法理解为什么您立即释放分配的内存C.CString
。手册说:
// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CString(string) *C.char
因此,您似乎在将指向它们的指针分配给相应的数组条目对之后立即解除分配键/值对的内存块。我怀疑这是一个错误:必须在 C 函数完成执行后进行释放。
2019 年 7 月 26 日更新:
这是工作代码:
package main
/*
#include <stdio.h>
#include <stdlib.h>
void writeKeyValuePairs(char *v[][2], size_t len) {
int i;
for (i = 0; i < len; i++) {
printf("i=%i, k=%s, v=%s\n", i, v[i][0], v[i][1]);
}
return;
}
*/
import "C"
import "unsafe"
func main() {
tags := map[string]string{
"foo": "42",
"bar": "12",
}
var argv = make([][2]*C.char, len(tags))
i := 0
for key, val := range tags {
var kv [2]*C.char
kv[0], kv[1] = C.CString(key), C.CString(val)
argv[i] = kv
i++
}
defer func(items [][2]*C.char) {
for i := range items {
k, v := items[i][0], items[i][1]
C.free(unsafe.Pointer(k))
C.free(unsafe.Pointer(v))
}
}(argv)
C.writeKeyValuePairs(&argv[0], C.size_t(len(tags)))
}
结果:
$ go build c.go
$ ./c
i=0, k=foo, v=42
i=1, k=bar, v=12
推荐阅读
- java - Spring Boot Web 应用程序在 Internet 中托管
- ios - React Native Reload Screen A In Back 动作
- android-studio - 任务 ':app:transformDexArchiveWithExternalLibsDexMergerForDebug 执行失败
- c++ - 如何在 qml 应用程序窗口中隐藏最大化和最小化按钮并显示关闭按钮?
- f# - 如何从记录类型中调用字段?
- algorithm - 从最大堆中删除叶节点的时间复杂度?
- powershell - 指定的提供程序类型无效。加密异常
- node.js - 在续集的.sum() 中得到范围错误?
- c# - 为 2 个不同的 Web 应用程序上传文件位置
- jetty - 使用 MQ 连接的码头配置时,WebSphere MQ 调用失败,compcode '2' ('MQCC_FAILED') 原因 '2397' ('MQRC_JSSE_ERROR')