根据文档,go build使用 cgo 将在包的根目录中添加任何 C/C++ 文件作为编译的一部分。有没有办法通过使用 CGO 指令使给定子目录中的 C/C++ 文件也成为编译的一部分以及根目录中的文件?
我正在尝试与 Go 中的一些 C 代码交互。使用 cgo,这一直相对简单,直到我遇到这种(相当常见的)情况:需要将指针传递给本身包含指向某些数据的指针的结构。如果不诉诸于将结构的创建放入 C 代码本身,我似乎无法弄清楚如何从 Go 中做到这一点,我不想这样做。这是一个说明问题的片段:
package main
// typedef struct {
// int size;
// void *data;
// } info;
//
// void test(info *infoPtr) {
// // Do something here...
// }
import "C"
import "unsafe"
func main() {
var data uint8 = 5
info := &C.info{size: C.int(unsafe.Sizeof(data)), data: unsafe.Pointer(&data)}
C.test(info)
}
Run Code Online (Sandbox Code Playgroud)
虽然编译正常,但尝试运行它会导致:
panic: runtime error: cgo argument has Go pointer to Go pointer
Run Code Online (Sandbox Code Playgroud)
在我的例子中,传递给 C 调用的数据在调用后不会持续存在(即,有问题的 C 代码深入结构,复制它需要的内容,然后返回)。
背景:使用 cgo 从 Golang 调用 C 函数。
我想用它有这个签名C函数:int f(int *count, char ***strs)。它将修改countand的数据strs,这就是它使用指向它们的指针的原因。的值count是 的长度strs;strs是一个字符串数组;返回值只是一个(布尔值)指示符,用于说明是否存在错误。
在golang中,我可以count通过使用成功通过和修改C.f((*C.int)(&count));通过[]string使用[]*C.char. 示例代码是这样的:
/*
#include <stdio.h>
int f(int *c, char **str) {
int i;
printf("%d\n", *c);
for (i = 0; i < *c; i++) {
printf("%s\n", str[i]);
}
*c = (*c) + 1;
return 1;
}
*/
import "C"
func go_f(strs []string) int {
count := len(strs)
c_count …Run Code Online (Sandbox Code Playgroud) cgo 在 go 中写在“comments”中,这意味着默认情况下它被赋予注释语法突出显示。有适当的 golang和C 语法突出显示会很好,但在 cgo 文件中。
package main
// ... C code or #include here ...
import "C"
... Go code here ...
Run Code Online (Sandbox Code Playgroud)
无论是 Visual Studio Code 还是 ViM,我都喜欢这个。
如何做到这一点?
我试图找出调用此函数的正确方法:
size_t
fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap)
{
if (datap)
*datap = (buf ? buf->data : NULL);
return (buf ? buf->len : 0);
}
Run Code Online (Sandbox Code Playgroud)
使用 CGo 获取底层字符串及其长度作为 Go 中的字节数组。
这是正确的方法吗?
var bufferContents *C.uchar
length := C.fz_buffer_storage(ctx, buf, &bufferContents)
bytes := C.GoBytes(unsafe.Pointer(bufferContents), C.int(length))
Run Code Online (Sandbox Code Playgroud)
由于 C 代码覆盖了*datap,我不确定垃圾收集器是否仍然会做正确的事情。
var tempUcharPtr *C.uchar
bufferContents := C.malloc(C.size_t(unsafe.Sizeof(tempUcharPtr)))
defer C.free(bufferContents)
length := C.fz_buffer_storage(ctx, buf, (**C.uchar)(bufferContents))
bytes := C.GoBytes(unsafe.Pointer(*(**C.uchar)(bufferContents)), C.int(length))
Run Code Online (Sandbox Code Playgroud)
这似乎也有效,但它更复杂,我想知道它是否比以前的版本更好/更安全。
我刚刚开始使用 CGo,我正在尝试将数据发送到 C 库,该库对浮点数/双精度数数组执行统计计算。我现在想弄清楚的是如何将浮点数组或 C.double 的数组发送到具有如下签名的 CGo 函数:
double pop_mean(int numPoints, double a[])
Run Code Online (Sandbox Code Playgroud)
我已经想出了如何在那里输入 C.int,但是我在弄清楚如何发送双打数组时遇到了麻烦。
我还没有看到任何关于这件事的博客文章或 SO 问题,所以我想我会问。
以下是我迄今为止最大的努力。
// Get a basic function to work, while passing in an ARRAY arr := make([]C.double, 0)
arr = append(arr, C.double(10.0))
arr = append(arr, C.double(20.0))
arr = append(arr, C.double(30.0))
var fixedArray [3]C.double = arr[:]
// ptr := C.CBytes(arr)
// defer C.free(unsafe.Pointer(ptr))
coolMean := C.pop_mean(3, &fixedArray)
fmt.Println("pop_mean (10, 20, 30): ", coolMean)
Run Code Online (Sandbox Code Playgroud)
这是我得到的错误:
./main.go:64:6: cannot use arr[:] (type []_Ctype_double) as type [3]_Ctype_double in …Run Code Online (Sandbox Code Playgroud) 结构的内存已经分配。
我想在 golang 中接近 C 结构。
我想在没有c代码的情况下访问golang中的struct变量,我该怎么办?
package main
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int num;
char food[10];
char animal[128];
} sample;
sample *sa;
static void alloc() {
sa = (sample *) malloc (sizeof(sample) * 2);
memset(sa, 0, sizeof(sample) * 2);
sa[0].num = 10;
strcpy(sa[0].food, "noodle");
strcpy(sa[0].animal, "cat");
sa[1].num = 20;
strcpy(sa[1].food, "pizza");
strcpy(sa[1].animal, "dog");
}
*/
import "C"
import "fmt"
func init() {
C.alloc()
}
func main() {
fmt.Println(C.sa[0].num)
fmt.Println(C.sa[0].food)
fmt.Println(C.sa[0].animal)
fmt.Println(C.sa[1].num)
fmt.Println(C.sa[1].food)
fmt.Println(C.sa[1].animal) …Run Code Online (Sandbox Code Playgroud) 我有一个像这样的结构:
typedef struct st_MASK_SETTINGS
{
uint32_t foo : 1;
uint32_t bar : 7;
} MASK_SETTINGS
Run Code Online (Sandbox Code Playgroud)
现在我想通过 cgo 访问foo- 但找不到任何文档如何做到这一点。
天真的v := ms.foo抱怨has no field or method。
我有一个使用 Qt 包装器库https://github.com/therecipe/qt的 Go 程序。不幸的是,它的构建时间变得非常长(假设它是 go 部分)
go build -i . // takes about 14 seconds
go run . // takes about 8 seconds
Run Code Online (Sandbox Code Playgroud)
运行上述任一命令后,我在$GOPATH/pkg/linux_amd64/github.com/therecipe/qtas.a文件中获得了预编译的依赖项,因此它们不会每次都重新构建。
我尝试使用https://github.com/therecipe/qt/wiki/Faster-builds-(Linux) 中描述的ccacheGold 链接器/usr/bin/ld.gold,但它没有任何改进。这个 Qt 包装器也附带了我尝试过的自己的构建工具,但它的构建时间大致相同。qtdeploy
我正在运行的系统:
go version go1.14.4 linux/amd64
Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
16GB Ram
Run Code Online (Sandbox Code Playgroud)
有谁知道是否有可能至少改善一点构建时间?
编辑:
运行go build -x .显示最大的时间消费者是以下命令
~/.go/pkg/tool/linux_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=k8lYa6JYqRdCY9Gyt0jX/16myMybByG5X6rOfaRpS/WHdW2kCTfMCZs2I4x9WE/k8lYa6JYqRdCY9Gyt0jX -extld=g++ ~/.cache/go-build/b5/b5e47b7f77c2df06ba69937dc8b1399b1289b7c90d2e08b3341fdf13e119c860-d
Run Code Online (Sandbox Code Playgroud) 根据 CGO 的文档(https://pkg.go.dev/cmd/cgo),在实现中有一个已知的错误:
注意:当前的实现有一个错误。虽然 Go 代码允许将 nil 或 C 指针(但不是 Go 指针)写入 C 内存,但如果 C 内存的内容看起来是 Go 指针,当前实现有时可能会导致运行时错误。因此,如果 Go 代码要在其中存储指针值,请避免将未初始化的 C 内存传递给 Go 代码。在将 C 中的内存传递给 Go 之前将其清零。
我在 GitHub 的问题跟踪器中寻找过这个,但在那里找不到。有人可以详细说明为什么会发生这种情况吗?运行时如何在未初始化的 C 内存中找到 Go 指针?
例如。假设我将一个未初始化的字符数组传递给 C 中的 Go 函数,运行时如何解释该内存中的 Go 指针?
此外,“如果 Go 代码将在其中存储指针值”部分让我感到困惑。为什么以后使用这个内存很重要?