IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Go语言和C语言之间实现内存共享的坑 -> 正文阅读

[C++知识库]Go语言和C语言之间实现内存共享的坑

摘要

在Go和C内存共享时,可能会出现错误cgo argument has Go pointer to Go pointer。该问题出现的主要原因是在Go1.6.2版本之后,GO语言的rumtime检查机制对C和GO之间的指针传递行为进行了强制检查,不允许传递指向Go内存地址的指针。

正文

在Go1.6.2版本之后,Go的runtime加入了指针违规传递检测机制。该机制主要针对Go向C传递带有指向其他Go内存的地址,具体见文献检查机制

  • 情况1 不能传递带有初始化内存空间的指针切片
package main

//#cgo CFLAGS: -std=c99
/*
#include <stdio.h>
#include <stdlib.h>

void array(int** arr,int n){
	for (int i=0;i<n;i++){
		*arr=(int*)malloc(sizeof(int));
		**arr=i+i;
		arr++;
	}
}
*/
import "C"
import (
	"fmt"
	"runtime"
	"unsafe"
)

func main() {
	fmt.Printf("Allocate a memory through Golang coding.\n");
	c:=make([]*C.int,3);
	for i,_:=range c{
		fmt.Println(i,c[i])
	}
	//"Pass the first pointer of the memory to C code to process.
	C.array((**C.int)(unsafe.Pointer(&c[0])),3);
	fmt.Printf("Display the processing result.\n")
	for i,_:=range c{
		fmt.Println(i,c[i],*c[i]);
	}
	runtime.GC();
}

执行结果:
在这里插入图片描述

package main

//#cgo CFLAGS: -std=c99
/*
#include <stdio.h>
#include <stdlib.h>

void array(int** arr,int n){
	for (int i=0;i<n;i++){
		*arr=(int*)malloc(sizeof(int));
		**arr=i+i;
		arr++;
	}
}
*/
import "C"
import (
	"fmt"
	"runtime"
	"unsafe"
)

func main() {
	fmt.Printf("Allocate a memory through Golang coding.\n");
	c:=make([]*C.int,3);
	for i,_:=range c{
		c[i]=new(C.int)
		fmt.Println(i,c[i])
	}
	//"Pass the first pointer of the memory to C code to process.
	C.array((**C.int)(unsafe.Pointer(&c[0])),3);
	fmt.Printf("Display the processing result.\n")
	for i,_:=range c{
		fmt.Println(i,c[i],*c[i]);
	}
	runtime.GC();
}

执行结果:
在这里插入图片描述

  • 情况2 Go不能向C传递带有初始化内存空间的结构体
package main

//#cgo CFLAGS: -std=c99
/*
#include <stdio.h>
#include <stdlib.h>

typedef struct{
	int* Number;
}A;


void transfer(A *a){
	if (a->Number==NULL){
       a->Number=(int*)malloc(sizeof(int));
	}
	*(a->Number)=4;
}

*/
import "C"
import (
	"fmt"
	"unsafe"
)

func main() {
	var S A
	fmt.Printf("*****before being transfered to C!\n");
	S.Number=new(C.int)
	fmt.Println(S.Number)
	C.transfer((*C.A)(unsafe.Pointer(&S)))
	fmt.Printf("*****after being transfered to C!\n");
	fmt.Println(*S.Number)

}

type A struct{
	Number *C.int
}

执行结果
在这里插入图片描述

  • 情况3 不能传递指向已知内存的指针给C语言
package main

//#cgo CFLAGS: -std=c99
/*
#include <stdio.h>
#include <stdlib.h>

typedef struct{
	int* Number;
}A;


void transfer(int **a){
     printf("*=%p,**a=%d\n",*a,**a);
	 printf("fix value of point to 16\n");
	 **a=16;
}

*/
import "C"
import "fmt"

func main() {
	point:=new(C.int);
	*point=4;
	fmt.Println("******before being transfered to C Code!")
	fmt.Printf("point=%p,*point=%d\n",point,*point)
	C.transfer(&point);
	fmt.Printf("point=%p,*point=%d\n",point,*point)
}

执行结果为
在这里插入图片描述

解决办法

解决办法主要有两类,临时性解决和永久性解决。临时性解决主要针对某次编译绕开检测,缺点是每次执行都要带参数GODEBUG=cgocheck=0这个标识;永久性解决则将该GODEBUG=cgocheck=0做成系统环境变量,使每次运行都自动调用该参数。

  • 临时性解决

在编译开始时,加入GODEBUG=cgocheck=0,绕开rutime的编译检查机制,具体执行方法如下所示:
在这里插入图片描述

  • 永久性解决

将GODEGUG=cgocheck=0,加入Linux系统的~/.bashrc文件的末尾,实现启动默认添加该变量。
在这里插入图片描述
执行结果为
在这里插入图片描述

总结

在CGO交互中,出现报错cgo argument has Go pointer to Go pointer情形的主要原因是,GO语言的rumtime检查机制对C和GO之间的指针传递行为进行了强制检查。绕开检查机制是目前已知的处理方式。其实,为了避免导致不必要的内存泄露,尽量不用上述的指针传递方式进行C语言和GO的内存共享。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-11 23:48:36  更:2022-01-11 23:50:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:43:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码