英文:
How to add a golang string to a c struct in cgo
问题
如何将我在cgo中创建的c结构体中的golang字符串添加到c结构体中?以下是代码:
package main
/*
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
typedef struct Point {
int x, y;
} Point;
typedef struct Resp {
char response;
} Resp;
*/
import "C"
import (
"fmt"
"unsafe"
)
type CPoint struct {
Point C.Point
Resp C.Resp
}
func main() {
var r string = "Hello World"
resp := unsafe.Pointer(C.CString(r))
point := CPoint{
Point: C.Point{x: 1, y: 2},
Resp: C.Resp{response: *(*C.char)(resp)},
}
fmt.Println(point)
}
但是每当我运行这段代码时,我会得到以下错误:
cannot convert r (type string) to type _Ctype_char
我该如何解决这个问题?如何将r转换为类型_Ctype_char?
另外,你如何获取c结构体"Resp"中的值?
package main
/*
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
typedef struct Point {
int x, y;
} Point;
typedef struct Resp {
char response; // <-- 我该如何在我的go代码中获取这个值?
} Resp;
*/
英文:
How do I add a golang string to a c struct that I made in cgo. Heres the code:
package main
/*
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
typedef struct Point {
int x, y;
} Point;
typedef struct Resp {
char response;
} Resp;
*/
import "C"
import (
"fmt"
"io/ioutil"
"unsafe"
)
type CPoint struct {
Point C.Point
Resp C.Resp
}
func main() {
var r string = "Hello World"
resp := unsafe.Pointer(C.char(r))
point := CPoint{
Point: C.Point{x: 1, y: 2},
Resp: C.Resp{response: resp},
}
fmt.Println(point)
}
But whenever I run this I get this error
cannot convert r (type string) to type _Ctype_char
How do I fix this? How can I conver r to type _Ctype_char?
Also how would you get the value in the c struct "Resp"?
package main
/*
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
typedef struct Point {
int x, y;
} Point;
typedef struct Resp {
char response; // <-- How can I get this value in my go code?
} Resp;
*/
答案1
得分: 2
你的代码需要两处修复:
- C中的
char
只表示一个字符/字节,而不是字符串。C字符串应该使用char*
表示。 - 你应该使用
C.CString
从Go中分配一个C字符串,并使用C.free
释放它。参考:https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C。
以下是修复后的示例代码:
package main
// FIX: 将 "char response" 替换为 "char *response"。
/*
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
typedef struct Point {
int x, y;
} Point;
typedef struct Resp {
char *response;
} Resp;
void fill(const char *name, Resp *r) {
printf("name: %s\n", name);
printf("Original value: %s\n", r->response);
r->response = "testing";
}
*/
import "C"
import (
"fmt"
"unsafe"
)
// 注意:你不能将此结构体传递给C。
// 传递给C的类型必须在C中定义(例如上面的 "Point")。
type CPoint struct {
Point C.Point
Resp C.Resp
}
func main() {
// FIX: 使用CString来分配一个*C.char字符串。
resp := C.CString("Hello World")
point := CPoint{
Point: C.Point{x: 1, y: 2},
Resp: C.Resp{response: resp},
}
fmt.Println(point)
// 调用C函数并将C *char字符串转换为Go字符串的示例:
cname := C.CString("foo")
defer C.free(unsafe.Pointer(cname))
r := &C.Resp{
response: resp, // 使用分配的C字符串。
}
C.fill(cname, r)
goResp := C.GoString(r.response)
fmt.Println(goResp)
// FIX: 当不再需要手动分配的字符串时,使用free(3)进行释放。
C.free(unsafe.Pointer(resp))
}
以上是修复后的代码。
英文:
Your code needs 2 fixes:
- C
char
only represents a single character/byte - not a string. C strings arechar*
. - You should use
C.CString
to allocate a C string from Go, andC.free
to release it. See: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C.
Here is your example with these fixes:
package main
// FIX: "char response" replaced with "char *response" below.
/*
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
typedef struct Point {
int x, y;
} Point;
typedef struct Resp {
char *response;
} Resp;
void fill(const char *name, Resp *r) {
printf("name: %s\n", name);
printf("Original value: %s\n", r->response);
r->response = "testing";
}
*/
import "C"
import (
"fmt"
"unsafe"
)
// NOTE: You cannot pass this struct to C.
// Types passed to C must be defined in C (eg, like "Point" above).
type CPoint struct {
Point C.Point
Resp C.Resp
}
func main() {
// FIX: Use CString to allocate a *C.char string.
resp := C.CString("Hello World")
point := CPoint{
Point: C.Point{x: 1, y: 2},
Resp: C.Resp{response: resp},
}
fmt.Println(point)
// Example of calling a C function and converting a C *char string to a Go string:
cname := C.CString("foo")
defer C.free(unsafe.Pointer(cname))
r := &C.Resp{
response: resp, // Use allocated C string.
}
C.fill(cname, r)
goResp := C.GoString(r.response)
fmt.Println(goResp)
// FIX: Release manually allocated string with free(3) when no longer needed.
C.free(unsafe.Pointer(resp))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论