gpt4 book ai didi

go - 从指向 C-Char 数组的指针中获取字符串数据

转载 作者:行者123 更新时间:2023-12-01 22:37:22 25 4
gpt4 key购买 nike

我从 C++ dll 获得指向 C-char 数组的指针。如何获取字符串数据?

我正在使用此代码来获取指向内存地址的指针:

Go:

dll, err := windows.LoadDLL("someDll.dll")
if err != nil {
panic(err)
}
proc := dll.MustFindProc("Function")
response, _, _ := proc.Call()

C++ 代码:
extern "C" __declspec(dllexport) char* Function() {
char text[] = "something";
return text;
}

我试过这个:
fmt.Println(*(*string)(unsafe.Pointer(&response)))

还有这个:
var data []byte
sh := (*reflect.SliceHeader)(unsafe.Pointer(&data))
sh.Data = response
sh.Len = 9
sh.Cap = 9
fmt.Println(data, string(data))

但没有什么对我有用。

最佳答案

您的示例 C++ 代码......不好,因为它返回一个指向已释放存储的变量的指针。使用static char text[]或类似的修复它。真正的 C 或 C++ 代码将返回指向内存的指针,该指针应使用 free 释放。 ,或者不是,你也需要处理这些情况。

尽管如此,您仍然可以通过 cgo 获得部分或大部分您想要的结果。 , 这些天内置于 Go 中。注意使用cgo时需要单独的import "C"声明,通常以注释为前缀。 (您不能将此导入放入常规导入部分。)

让我们分几个部分来介绍所有这些。

没有 DLL,C 代码返回指向 static 的指针存储期限 char s

如果我们忽略所有 DLL 方面,并假设您可以直接链接到返回 char * 的特定 C 函数,使用它的示例 Go 代码将是:

package main

/*
extern char *Function();
*/
import "C"

import (
"fmt"
)

func WrapFunction() string {
return C.GoString(C.Function())
}

func main() {
fmt.Println(WrapFunction())
}

我放了一个 sample Function()在一个名为 cgo.go 的文件中在只有一个 .c 的目录中文件, function.c ,以及。这是此特定 Function() 的非常简单的 C 代码:

char *Function() {
return "hello";
}

(C 字符串文字的类型为 char [N],整数常量 N 在编译时确定,并且是静态持续时间,而 C 有一个有趣的规则,即把数组“衰减”为指向其第一个元素的指针,所以我们实现了我们的目标返回 char * 指向静态持续时间内存。)

$ go build
$ ./cgo
hello
$

返回指向动态分配内存的 C 代码

假设 C(或封装的 C++)函数使用 malloc (或 new )分配字符串,因此我们必须释放它。这是更新的 function.c这样做:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

char *Function() {
char *text = malloc(25); /* big enough for hello and a number */
if (text != NULL) {
srand(time(NULL)); /* should do this just once, really */
sprintf(text, "hello %d", rand() % 100);
}
return text;
}

然后我们将重写 cgo.go作为:

package main

/*
#include <stdlib.h>
extern char *Function();
*/
import "C"

import (
"fmt"
"unsafe"
)

func WrapFunction() string {
s := C.Function()
// Optional -- note that C.free(nil) is a no-op,
// and (by experimentation) C.GoString(nil) returns "".
// So, if it's OK to use "" if `C.Function` returns NULL,
// skip this test-and-panic.
if s == nil {
panic("C.Function returned NULL")
}
defer C.free(unsafe.Pointer(s))
return C.GoString(s)
}

func main() {
fmt.Println(WrapFunction())
}

编译并运行显示:

$ go build
$ ./cgo
hello 27

另见 https://blog.golang.org/c-go-cgohttps://golang.org/cmd/cgo/ .

动态链接库

以上都假设 C 包装器位于 build 目录中。运行 go build发现这一点并构建 function.c到一个目标文件,在 C 和 Go 之间添加所有必要的运行时接口(interface),并调用函数 Function直接,按名称。

如果您必须在运行时确定函数名称,您将遇到更严重的问题。问题的核心是您无法从 cgo 获得帮助。直接包装函数,因为 cgo 需要在 import "C" 上方的注释中查看函数的名称线。

how to import a DLL function written in C using GO?对于几种方法。另一个未列出的方法是在您自己编写的 C 包装器中进行 DLL 查找。使用 cgo传递要查找的函数的名称以及所有(固定)参数。然后,您正在调用具有已知(编译时)返回类型和值的已知(编译时)函数,这简化了问题。 cgo 运行时包装器将为您的已知函数插入适当的运行时堆栈切换,因此您不必使用 syscall wrapper 。

关于go - 从指向 C-Char 数组的指针中获取字符串数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59010986/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com