从C语言向Golang传递uint8_t数组的方法

从C语言向Golang传递uint8_t数组的方法 大家好,

我是 Go 语言的新手 🙂,我想从 C 语言向 Go 语言发送一个 uint8_t 数组,但是当我以指针形式发送数组时,我不知道如何在 Go 中读取它并将其保存为 byte[] 数组类型。 以下是我的代码:

package main
/*
#include <stdint.h>

uint8_t Plaintext[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

uint8_t * send_data( )
   {
     return  Plaintext;
   }

*/
import "C"
import "unsafe"
import "fmt"

func main() {

    data := [16]byte{}
    p := C.send_data()
    //already try  data = C.send_data()
    fmt.Println(p)
    data = p // don't know how do this ?

}

目标是在 Go 中获得一个如下的字节数组:

data[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}

我尝试了很多解决方案,但每次都收到日志提示“无法使用 (func literal)() (类型 *_Ctype_uchar) 作为类型 “uint8” 或 “byte” …”。

谢谢大家的帮助!


更多关于从C语言向Golang传递uint8_t数组的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

你好 @skillian

感谢你的回复,我使用了你描述的第二种解决方案,效果很好。

关于同一主题,我还有一个问题!你知道如何将变量放入数组的边界中吗?

替换这行:
p16byte := *((*[16]byte)(unsafe.Pointer(p)))

为:
int lens_var = 16
p16byte := *((*[lens_var]byte)(unsafe.Pointer(p)))

但这行不通,因为它无法编译。我也尝试使用切片,但同样不起作用:

int lens_var = 16
var type_var= make([]byte, lens_var )
p16byte := *((*type_var)(unsafe.Pointer(p)))

也许我忽略了一些细节!!!

再次感谢

更多关于从C语言向Golang传递uint8_t数组的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好,Jawad,

你的 send_data 函数返回值的 Go 类型是 *_Ctype_uchar,它不能被直接赋值给一个 [16]byte 数组。有几种方法可以解决这个问题。一种方法是使用 unsafe.Pointer 类型配合 C.GoBytes 辅助函数:

package main

/*
#include <stdint.h>

uint8_t Plaintext[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

uint8_t * send_data( )
   {
     return  Plaintext;
   }

*/
import "C"
import "unsafe"
import "fmt"

func main() {

    data := [16]byte{}
    p := C.GoBytes(unsafe.Pointer(C.send_data()), 16)
    fmt.Println(p)
    copy(data[:], p)
    fmt.Printf("%T: %v\n", data, data)
}

我认为这是正确的方法。另一种方法是转换那个 unsafe.Pointer,并直接将其转换为 *[16]byte

package main

/*
#include <stdint.h>

uint8_t Plaintext[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

uint8_t * send_data( )
   {
     return  Plaintext;
   }

*/
import "C"
import "unsafe"
import "fmt"

func main() {

    data := [16]byte{}
    p := C.send_data()
    fmt.Println(p)
    p16byte := *((*[16]byte)(unsafe.Pointer(p)))
    data = p16byte
    fmt.Printf("%T: %v\n", data, data)
}

在Go中处理C返回的uint8_t*指针,可以通过unsafe.Pointer和切片转换实现。以下是修改后的代码:

package main

/*
#include <stdint.h>

uint8_t Plaintext[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

uint8_t* send_data() {
    return Plaintext;
}
*/
import "C"
import (
    "fmt"
    "unsafe"
)

func main() {
    // 获取C指针
    cPtr := C.send_data()
    
    // 将C指针转换为Go的unsafe.Pointer
    ptr := unsafe.Pointer(cPtr)
    
    // 创建指向16字节数组的指针
    var data *[16]byte
    data = (*[16]byte)(ptr)
    
    // 打印结果
    fmt.Printf("Data: %v\n", *data)
    
    // 如果需要复制到新的Go数组(避免共享内存)
    goArray := *data
    fmt.Printf("Go array: %v\n", goArray)
    
    // 或者直接作为切片使用
    slice := (*data)[:]
    fmt.Printf("Slice: %v\n", slice)
}

如果需要处理动态长度的数组,可以使用切片转换:

func main() {
    cPtr := C.send_data()
    ptr := unsafe.Pointer(cPtr)
    
    // 假设已知长度为16
    length := 16
    
    // 转换为切片
    slice := (*[1 << 30]byte)(ptr)[:length:length]
    
    fmt.Printf("Slice (len=%d, cap=%d): %v\n", 
        len(slice), cap(slice), slice)
    
    // 复制到新的Go切片(独立内存)
    goSlice := make([]byte, length)
    copy(goSlice, slice)
    fmt.Printf("Copied slice: %v\n", goSlice)
}

注意:直接使用unsafe.Pointer转换访问C内存时,需要确保C内存的有效期。如果C函数返回的是局部变量的指针,可能会出现问题。

回到顶部