golang学习笔记-golang调用c实现的.so接口细节

目的

之前有一篇关于 在windows平台下golang调用dll的具体实现 ,列举了常见的几种参数传递方式,本篇文章就针对在linux平台下使用cgo调用c实现的.so的一些具体的方式。比如值传递、参数传递、指针等等的一些使用。

环境:centos 7.6.18
编译环境:go1.11.4 linux/amd644.8.5 20150623 (Red Hat 4.8.5-36) (GCC)

一、动态库的实现

动态库实现了三个功能,单个无参函数的;单个结构体函数;多个结构体函数
def.h

#ifndef _DEF_H_
#define _DEF_H_
// 结构体
struct userinfo
{
    char* username;
    int len;
};
#endif

hello.h

#ifndef _CALL_H_
#define _CALL_H_
#include "def.h"

void helloworld();
void store_jpg(char* name , int len);
void only_struct(struct userinfo* u);
void multi_struct(struct userinfo* u,int size);
#endif //_CALL_H_

hello.c

#include "hello.h"
#include <stdio.h>
#include <stdlib.h>

// helloworl
void helloworld()
{
    printf("hello world.\n");
}

// 指针和int 模拟存文件
void store_jpg(char* name ,int len)
{
    FILE *fp = NULL;
    fp = fopen( "file.jpg" , "w" );
    fwrite(name, len , 1, fp );
    fclose(fp); 
}

// 调用结构体指针
void only_struct(struct userinfo* u)
{
    char* name =u->username;
    int len = u->len;
    printf("call_only_struct:%s %d\n",name,len);
}

// 调用结构体指针,模拟结构体数组
void multi_struct(struct userinfo* u,int size)
{
    int i = 0;
    printf("call_multi_struct\n");
    while (i < size)
    {
        char* name = u[i].username;
        int len = u[i].len;
        printf("username:%s, len:%d, size:%d\n",name,len,size);
        i++;
    }    
}

测试动态库是否正常的c代码main.c

#include <stdio.h>
#include "def.h"

// 调用 libhello.so  测试动态库
int main()
{
    helloworld();
    struct userinfo u = {"shadiao wangyou",sizeof("shadiao wangyou")};
    only_struct(&u);
    return 0;
}

实现两个接口,一个打印hello world,一个存储文件。

二、golang代码

1、golang调用.so的代码

1)调用单个的无参函数
2)调用指针和长度,在大部分的场景中都会用到
3)调用单个的结构体,数据结构使用的是c代码中定义的结构
4)调用多个结构体

package main
/*
#cgo CFLAGS : -I../c
#cgo LDFLAGS: -L../c -lhello

#include "hello.h"
#include <stdio.h>
#include <stdlib.h>
*/
import "C"
import (
	"os"
	"unsafe"
	"fmt"
)
func main(){
	call_helloworl()
	call_store_file()
	call_only_struct()
	call_multi_struct()
}

func call_helloworl(){
	C.helloworld()
}

func call_store_file(){
	f,err:=os.Open("1.jpg")
	if err!=nil{
		panic(err)
	}
	defer f.Close()
	buf:=make([]byte,1024*10)
	if n,err:=f.Read(buf);err!=nil{
		panic(err)
	}else{
		cs:=C.CString(string(buf[0:n]))
		defer C.free(unsafe.Pointer(cs))
		C.store_jpg(cs, C.int(n))
	}
}

func call_only_struct(){
	var userinfo C.struct_userinfo
	cs:= C.CString("shadiao wangyou")
	defer C.free(unsafe.Pointer(cs))
	userinfo.username =cs
	userinfo.len = C.int(len("shadiao wangyou"))
	C.only_struct(&userinfo)
}

func call_multi_struct(){
	var userinfos []C.struct_userinfo
	for i:=0;i<2;i++{
		var ui C.struct_userinfo
		s:=fmt.Sprintf("%s-%d","shadiao wangyou",i)
		cs:= C.CString(s)
		defer C.free(unsafe.Pointer(cs))
		ui.username =cs
		ui.len = C.int(len(s))

		userinfos=append(userinfos,ui)
	}
	C.multi_struct(&userinfos[0],C.int(len(userinfos)))
}

2、代码结构和编译脚本

cgo
├── c
│   ├── hello.c
│   ├── hello.h
│   ├── libhello.a
│   ├── libhello.so
│   ├── main
│   ├── main.c
│   ├── make.sh
│   └── static_main
└── go
    ├── libhello.so
    ├── main
    └── main.go

编译脚本make.sh

#/bin/bash
echo "static lib"
rm -rf ./*.o 
rm -rf ./*.a
rm -rf main

gcc -c -o hello.o hello.c
ar -rc libhello.a hello.o
gcc main.c libhello.a -L. -o static_main

rm -rf ./*.o 
echo "lib"
rm -rf /usr/lib64/libhello.so
gcc -fPIC -shared hello.c -o libhello.so
sudo cp libhello.so /usr/lib64/
gcc main.c -L. -lhello -o main

三、结果

生成的动态库:

在这里插入图片描述

调用的结果:

在这里插入图片描述
参考链接:
http://blog.codeg.cn/post/blog/2016-04-20-golang-cgo/

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值