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

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

How to add a golang string to a c struct in cgo

问题

如何将我在cgo中创建的c结构体中的golang字符串添加到c结构体中?以下是代码:

  1. package main
  2. /*
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <errno.h>
  6. typedef struct Point {
  7. int x, y;
  8. } Point;
  9. typedef struct Resp {
  10. char response;
  11. } Resp;
  12. */
  13. import "C"
  14. import (
  15. "fmt"
  16. "unsafe"
  17. )
  18. type CPoint struct {
  19. Point C.Point
  20. Resp C.Resp
  21. }
  22. func main() {
  23. var r string = "Hello World"
  24. resp := unsafe.Pointer(C.CString(r))
  25. point := CPoint{
  26. Point: C.Point{x: 1, y: 2},
  27. Resp: C.Resp{response: *(*C.char)(resp)},
  28. }
  29. fmt.Println(point)
  30. }

但是每当我运行这段代码时,我会得到以下错误:

cannot convert r (type string) to type _Ctype_char

我该如何解决这个问题?如何将r转换为类型_Ctype_char?

另外,你如何获取c结构体"Resp"中的值?

  1. package main
  2. /*
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <errno.h>
  6. typedef struct Point {
  7. int x, y;
  8. } Point;
  9. typedef struct Resp {
  10. char response; // <-- 我该如何在我的go代码中获取这个值?
  11. } Resp;
  12. */
英文:

How do I add a golang string to a c struct that I made in cgo. Heres the code:

  1. package main
  2. /*
  3. #include &lt;stdio.h&gt;
  4. #include &lt;stdlib.h&gt;
  5. #include &lt;errno.h&gt;
  6. typedef struct Point {
  7. int x, y;
  8. } Point;
  9. typedef struct Resp {
  10. char response;
  11. } Resp;
  12. */
  13. import &quot;C&quot;
  14. import (
  15. &quot;fmt&quot;
  16. &quot;io/ioutil&quot;
  17. &quot;unsafe&quot;
  18. )
  19. type CPoint struct {
  20. Point C.Point
  21. Resp C.Resp
  22. }
  23. func main() {
  24. var r string = &quot;Hello World&quot;
  25. resp := unsafe.Pointer(C.char(r))
  26. point := CPoint{
  27. Point: C.Point{x: 1, y: 2},
  28. Resp: C.Resp{response: resp},
  29. }
  30. fmt.Println(point)
  31. }

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"?

  1. package main
  2. /*
  3. #include &lt;stdio.h&gt;
  4. #include &lt;stdlib.h&gt;
  5. #include &lt;errno.h&gt;
  6. typedef struct Point {
  7. int x, y;
  8. } Point;
  9. typedef struct Resp {
  10. char response; // &lt;-- How can I get this value in my go code?
  11. } Resp;
  12. */

答案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。

以下是修复后的示例代码:

  1. package main
  2. // FIX: 将 "char response" 替换为 "char *response"。
  3. /*
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <errno.h>
  7. typedef struct Point {
  8. int x, y;
  9. } Point;
  10. typedef struct Resp {
  11. char *response;
  12. } Resp;
  13. void fill(const char *name, Resp *r) {
  14. printf("name: %s\n", name);
  15. printf("Original value: %s\n", r->response);
  16. r->response = "testing";
  17. }
  18. */
  19. import "C"
  20. import (
  21. "fmt"
  22. "unsafe"
  23. )
  24. // 注意:你不能将此结构体传递给C。
  25. // 传递给C的类型必须在C中定义(例如上面的 "Point")。
  26. type CPoint struct {
  27. Point C.Point
  28. Resp C.Resp
  29. }
  30. func main() {
  31. // FIX: 使用CString来分配一个*C.char字符串。
  32. resp := C.CString("Hello World")
  33. point := CPoint{
  34. Point: C.Point{x: 1, y: 2},
  35. Resp: C.Resp{response: resp},
  36. }
  37. fmt.Println(point)
  38. // 调用C函数并将C *char字符串转换为Go字符串的示例:
  39. cname := C.CString("foo")
  40. defer C.free(unsafe.Pointer(cname))
  41. r := &C.Resp{
  42. response: resp, // 使用分配的C字符串。
  43. }
  44. C.fill(cname, r)
  45. goResp := C.GoString(r.response)
  46. fmt.Println(goResp)
  47. // FIX: 当不再需要手动分配的字符串时,使用free(3)进行释放。
  48. C.free(unsafe.Pointer(resp))
  49. }

以上是修复后的代码。

英文:

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:

  1. package main
  2. // FIX: &quot;char response&quot; replaced with &quot;char *response&quot; below.
  3. /*
  4. #include &lt;stdio.h&gt;
  5. #include &lt;stdlib.h&gt;
  6. #include &lt;errno.h&gt;
  7. typedef struct Point {
  8. int x, y;
  9. } Point;
  10. typedef struct Resp {
  11. char *response;
  12. } Resp;
  13. void fill(const char *name, Resp *r) {
  14. printf(&quot;name: %s\n&quot;, name);
  15. printf(&quot;Original value: %s\n&quot;, r-&gt;response);
  16. r-&gt;response = &quot;testing&quot;;
  17. }
  18. */
  19. import &quot;C&quot;
  20. import (
  21. &quot;fmt&quot;
  22. &quot;unsafe&quot;
  23. )
  24. // NOTE: You cannot pass this struct to C.
  25. // Types passed to C must be defined in C (eg, like &quot;Point&quot; above).
  26. type CPoint struct {
  27. Point C.Point
  28. Resp C.Resp
  29. }
  30. func main() {
  31. // FIX: Use CString to allocate a *C.char string.
  32. resp := C.CString(&quot;Hello World&quot;)
  33. point := CPoint{
  34. Point: C.Point{x: 1, y: 2},
  35. Resp: C.Resp{response: resp},
  36. }
  37. fmt.Println(point)
  38. // Example of calling a C function and converting a C *char string to a Go string:
  39. cname := C.CString(&quot;foo&quot;)
  40. defer C.free(unsafe.Pointer(cname))
  41. r := &amp;C.Resp{
  42. response: resp, // Use allocated C string.
  43. }
  44. C.fill(cname, r)
  45. goResp := C.GoString(r.response)
  46. fmt.Println(goResp)
  47. // FIX: Release manually allocated string with free(3) when no longer needed.
  48. C.free(unsafe.Pointer(resp))
  49. }

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:

确定