c - how to copy C.int address into C.char in cgo?
问题描述
using cgo I am calling c function. I ran into situation where I have to copy C.int address into C.char[4]. Can I do that in go?
code snippet C- Structure:
struct data
{
char *a_add;
unsigned int length;
}
Go-Code
func main() {
var d[3] C.data
var filedescriptor C.int
d[0].a_add = &filedescriptor
d[0].length = 4
}
The problem is a_add is a char*. But I need to pass int variable address. The c-code is a legacy code, and I can't fix datatype now. Other C modules uses it, and it's working in C with a warning. where as in go, it is error.
Is there any way that I can copy address of int variable into char* array in cgo.
Update: I tried d[0].a_add = (*C.char)(unsafe.Pointer(&filedescriptor )),
getting Error: panic: runtime error: cgo argument has Go pointer to Go pointer
What Am I missing?
解决方案
One of the problems you are running into is that in a call into C code, you may not pass a pointer to a Go pointer. The variable filedescriptor
is a C.int
, but &filedescriptor
is a Go pointer, so you cannot use that (or rather, you cannot use that in the a_add
field as a value).
There is a great deal about your C code that is not clear to me, but you can probably use the code below. Note that this code may be overkill for your particular situation. It is not meant to be particularly efficient or good, just as clear as possible while being extremely flexible—for instance, it can read from and write to packed C structures.
package main
// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>
//
// struct data {
// char *a_add;
// unsigned int length;
// };
//
// void f(struct data *p) {
// printf("p->a_add = %p, p->length = %u\n", p->a_add, p->length);
// printf("p->a_add as an int: %d\n", *(int *)p->a_add);
// *(int *)p->a_add = 0x12345678;
// }
import "C"
import (
"fmt"
"unsafe"
)
const cIntSize = C.sizeof_int
// Produce a Go int64 from a C int. The caller passes the address
// of the C int.
func int64FromCInt(ci unsafe.Pointer) int64 {
// Get a slice pointing to the bytes of the C int.
sci := (*[cIntSize]byte)(ci)[:]
switch {
case cIntSize == unsafe.Sizeof(int64(0)):
var gi int64
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
copy(sgi, sci)
return gi
case cIntSize == unsafe.Sizeof(int32(0)):
var gi int32
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
copy(sgi, sci)
return int64(gi)
case cIntSize == unsafe.Sizeof(int(0)):
var gi int
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
copy(sgi, sci)
return int64(gi)
default:
panic("no Go integer size matches C integer size")
}
}
// Write C int (via an unsafe.Pointer) from Go int. The caller
// passes the address of the C int.
func writeCIntFromInt(gi int, ci unsafe.Pointer) {
// Get a slices covering the bytes of the C int.
sci := (*[cIntSize]byte)(ci)[:]
switch {
case cIntSize == unsafe.Sizeof(gi):
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi))[:]
copy(sci, sgi)
case cIntSize == unsafe.Sizeof(int64(0)):
// Copy value to int64 for copying purposes.
// Since int64 holds all int values, this always works.
gi2 := int64(gi)
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi2))[:]
copy(sci, sgi)
case cIntSize == unsafe.Sizeof(int32(0)):
// Copy value to int32 for copying purposes.
// Panic if we destroy the value via truncation.
gi2 := int32(gi)
if int(gi2) != gi {
panic(fmt.Sprintf("unable to send Go value %x to C: size of Go int=%d, size of C int=%d", gi, unsafe.Sizeof(gi), cIntSize))
}
sgi := (*[unsafe.Sizeof(gi)]byte)(unsafe.Pointer(&gi2))[:]
copy(sci, sgi)
default:
panic("no Go integer size matches C integer size")
}
}
func main() {
b := C.malloc(cIntSize)
defer C.free(b)
writeCIntFromInt(32767, b)
d := C.struct_data{a_add: (*C.char)(b), length: cIntSize}
fmt.Println("calling C.f(d)")
C.f(&d)
result := int64FromCInt(unsafe.Pointer(d.a_add))
fmt.Printf("result = %#x\n", result)
}
推荐阅读
- sockets - 停止/启动任何服务时的 MariaDB 消息
- javascript - 将信息传递给 Route 的子节点
- reactjs - React Js - 如果触发了 setState,则进行酶测试
- wordpress - 如何将 divi Menu.php 覆盖为子主题
- reactjs - 使用 useState 更新嵌套对象的值
- python - 使 Python 安装 praw 出现问题 - 语法错误?
- matlab - 我应该如何在 matlab 中更正我的程序?(排序应用程序)
- android - 如何在 Android API 级别 27 中禁用 SIM 插槽 1
- json - 从其中包含 json 格式的文本文件中正确读取数据
- python - 使用 Pylightxl 使用 Python 写入 Excel 工作表时出错