如何在cgo中将golang字符串添加到C结构体中

huangapple go评论88阅读模式
英文:

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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;errno.h&gt;

typedef struct Point {
	int x, y;
} Point;

typedef struct Resp {
	char response;
} Resp;
*/
import &quot;C&quot;
import (
	&quot;fmt&quot;
	&quot;io/ioutil&quot;
	&quot;unsafe&quot;
)

type CPoint struct {
	Point C.Point
	Resp  C.Resp
}

func main() {

	var r string = &quot;Hello World&quot;
	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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;errno.h&gt;

typedef struct Point {
    int x, y;
} Point;

typedef struct Resp {
    char response; // &lt;-- How can I get this value in my go code?
} Resp;
*/

答案1

得分: 2

你的代码需要两处修复:

  1. C中的char只表示一个字符/字节,而不是字符串。C字符串应该使用char*表示。
  2. 你应该使用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:

  1. C char only represents a single character/byte - not a string. C strings are char*.
  2. You should use C.CString to allocate a C string from Go, and C.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: &quot;char response&quot; replaced with &quot;char *response&quot; below.

/*
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;errno.h&gt;

typedef struct Point {
    int x, y;
} Point;

typedef struct Resp {
    char *response;
} Resp;

void fill(const char *name, Resp *r) {
   printf(&quot;name: %s\n&quot;, name);
   printf(&quot;Original value: %s\n&quot;, r-&gt;response);
   r-&gt;response = &quot;testing&quot;;
}
*/
import &quot;C&quot;
import (
	&quot;fmt&quot;
	&quot;unsafe&quot;
)

// NOTE: You cannot pass this struct to C.
// Types passed to C must be defined in C (eg, like &quot;Point&quot; above).
type CPoint struct {
	Point C.Point
	Resp  C.Resp
}

func main() {
	// FIX: Use CString to allocate a *C.char string.
	resp := C.CString(&quot;Hello World&quot;)

	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(&quot;foo&quot;)
	defer C.free(unsafe.Pointer(cname))
	r := &amp;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))
}

huangapple
  • 本文由 发表于 2021年9月22日 18:15:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/69282258.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定