将 *C.uint8_t 转换为 []uint8 安全吗?
Is it safe to convert *C.uint8_t to []uint8?
我正在尝试将 uint8_t 数组从 C 代码传递给 Go,然后从文件中读取一些字节并将它们存储到 Go 代码中的这个数组中。
示例代码在这里。
main.c :
#define BUFFER_SIZE 16384
int read_go(uint8_t* buffer, int bufferSize);
void read_buf() {
uint8_t* buffer = (uint8_t*)malloc(BUFFER_SIZE);
read_go(buffer, BUFFER_SIZE)
// do something with buffer
free(buffer)
}
read.go :
/*
#include "main.c"
extern int read_go(uint8_t* buffer, int bufferSize);
*/
import "C"
//export read_go
func read_go(buffer *C.uint8_t, bufferSize C.int) C.int {
f, _ := os.Open("filename")
defer f.close()
buff := *(*[]uint8)(unsafe.Pointer(&buffer))
n, _ := f.Read(buff)
return C.int(n)
}
它运行良好,但我担心分段错误。因为与 C 的 fread 函数不同,我无法在 Read 函数中指定缓冲区大小。
我知道 Read 函数从文件中读取字节与 len(buff) 一样多。但我不能保证 len(buff) 与 bufferSize 相同。
将 *C.uint8_t 转换为 []uint8 安全吗?
您的代码有误。
Go slice 实现为 Go struct
:
type slice struct {
array unsafe.Pointer
len int
cap int
}
您 slice.len
和 slice.cap
的值未定义。
Questions seeking debugging help ("why isn't this code working?") must
include the desired behavior, a specific problem or error and the
shortest code necessary to reproduce it in the question itself.
您的代码片段无法编译且不完整。
buf
是 Go byte
slice 满足 io.Reader
.
type Reader interface {
Read(p []byte) (n int, err error)
}
buffer *C.uint8_t
bufferSize C.int
buf := (*[1 << 30]byte)(unsafe.Pointer(buffer))[:bufferSize:bufferSize]
n, err := f.Read(buf)
这是我的可重现形式的解决方案。
main.c
:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFFER_SIZE 16384
int read_go(uint8_t* buffer, int bufferSize);
void read_buf() {
uint8_t* buffer = (uint8_t*)malloc(BUFFER_SIZE+1);
buffer[BUFFER_SIZE]='[=12=]';
int n = read_go(buffer, BUFFER_SIZE);
if (n < 0) {
printf("read_go: error: %d\n", n);
n = 0;
}
if (n > BUFFER_SIZE) {
n = BUFFER_SIZE;
}
buffer[n] = '[=12=]';
// do something with buffer
int width = n;
printf("%d\n", width);
if (width > 16) {
width = 16;
}
for (int i = 0; i < width; i++) {
printf("%02X", buffer[i]);
}
printf("\n");
for (int i = 0; i < width; i++) {
printf("%-2c", buffer[i]);
}
printf("\n");
free(buffer);
}
int main(int argc, char *argv[]) {
read_buf();
return EXIT_SUCCESS;
}
read.go
:
package main
/*
#include <stdint.h>
*/
import "C"
import (
"os"
"unsafe"
)
//export read_go
func read_go(buffer *C.uint8_t, bufferSize C.int) C.int {
f, err := os.Open("filename")
if err != nil {
return C.int(-1)
}
defer f.Close()
buf := (*[1 << 30]byte)(unsafe.Pointer(buffer))[:bufferSize:bufferSize]
n, err := f.Read(buf)
if err != nil {
return C.int(-1)
}
return C.int(n)
}
func main() {}
输出(Linux):
$ cat filename
filedata 01234567890
$ export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
$ go build -a -o libread.so -buildmode=c-shared read.go
$ gcc main.c libread.so -o read && ./read
21
66696C65646174612030313233343536
f i l e d a t a 0 1 2 3 4 5 6
$
我正在尝试将 uint8_t 数组从 C 代码传递给 Go,然后从文件中读取一些字节并将它们存储到 Go 代码中的这个数组中。
示例代码在这里。
main.c :
#define BUFFER_SIZE 16384
int read_go(uint8_t* buffer, int bufferSize);
void read_buf() {
uint8_t* buffer = (uint8_t*)malloc(BUFFER_SIZE);
read_go(buffer, BUFFER_SIZE)
// do something with buffer
free(buffer)
}
read.go :
/*
#include "main.c"
extern int read_go(uint8_t* buffer, int bufferSize);
*/
import "C"
//export read_go
func read_go(buffer *C.uint8_t, bufferSize C.int) C.int {
f, _ := os.Open("filename")
defer f.close()
buff := *(*[]uint8)(unsafe.Pointer(&buffer))
n, _ := f.Read(buff)
return C.int(n)
}
它运行良好,但我担心分段错误。因为与 C 的 fread 函数不同,我无法在 Read 函数中指定缓冲区大小。
我知道 Read 函数从文件中读取字节与 len(buff) 一样多。但我不能保证 len(buff) 与 bufferSize 相同。
将 *C.uint8_t 转换为 []uint8 安全吗?
您的代码有误。
Go slice 实现为 Go struct
:
type slice struct {
array unsafe.Pointer
len int
cap int
}
您 slice.len
和 slice.cap
的值未定义。
Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself.
您的代码片段无法编译且不完整。
buf
是 Go byte
slice 满足 io.Reader
.
type Reader interface {
Read(p []byte) (n int, err error)
}
buffer *C.uint8_t
bufferSize C.int
buf := (*[1 << 30]byte)(unsafe.Pointer(buffer))[:bufferSize:bufferSize]
n, err := f.Read(buf)
这是我的可重现形式的解决方案。
main.c
:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFFER_SIZE 16384
int read_go(uint8_t* buffer, int bufferSize);
void read_buf() {
uint8_t* buffer = (uint8_t*)malloc(BUFFER_SIZE+1);
buffer[BUFFER_SIZE]='[=12=]';
int n = read_go(buffer, BUFFER_SIZE);
if (n < 0) {
printf("read_go: error: %d\n", n);
n = 0;
}
if (n > BUFFER_SIZE) {
n = BUFFER_SIZE;
}
buffer[n] = '[=12=]';
// do something with buffer
int width = n;
printf("%d\n", width);
if (width > 16) {
width = 16;
}
for (int i = 0; i < width; i++) {
printf("%02X", buffer[i]);
}
printf("\n");
for (int i = 0; i < width; i++) {
printf("%-2c", buffer[i]);
}
printf("\n");
free(buffer);
}
int main(int argc, char *argv[]) {
read_buf();
return EXIT_SUCCESS;
}
read.go
:
package main
/*
#include <stdint.h>
*/
import "C"
import (
"os"
"unsafe"
)
//export read_go
func read_go(buffer *C.uint8_t, bufferSize C.int) C.int {
f, err := os.Open("filename")
if err != nil {
return C.int(-1)
}
defer f.Close()
buf := (*[1 << 30]byte)(unsafe.Pointer(buffer))[:bufferSize:bufferSize]
n, err := f.Read(buf)
if err != nil {
return C.int(-1)
}
return C.int(n)
}
func main() {}
输出(Linux):
$ cat filename
filedata 01234567890
$ export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
$ go build -a -o libread.so -buildmode=c-shared read.go
$ gcc main.c libread.so -o read && ./read
21
66696C65646174612030313233343536
f i l e d a t a 0 1 2 3 4 5 6
$