laid
是一个 cgo 的测试用例
使用下面实例 完成 cgo 库的学习
VS Code 配置
工作区
配置
- laid.code-workspace
{
"folders": [
{
"path": "."
}
],
"settings": {
"files.associations": {
"laid.h": "c"
}
}
}
C/C++ Extension Pack
配置:
- settings.json
控制错误提醒
{
"files.associations": {
"laid.h": "c"
},
"C_Cpp.errorSquiggles": "enabled"
}
- c_cpp_properties.json
配置代码提示
{
"configurations": [
{
"name": "Mac",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/include/"
],
"defines": [],
"macFrameworkPath": [
"/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks"
],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "macos-gcc-x64",
"mergeConfigurations": true
}
],
"version": 4
}
- tasks.json
配置代码编译
{
"tasks": [
{
"type": "cppbuild",
"label": "c 源码编译",
"command": "/usr/bin/gcc",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${workspaceFolder}/builds/${fileBasenameNoExtension}.o",
"-I", "${workspaceFolder}/include"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "调试器生成的任务。"
}
],
"version": "2.0.0"
}
- launch.json
配置 调试工具
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "gdb 启动",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/builds/main.out",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"preLaunchTask": "c 源码编译"
},
]
}
preLaunchTask
必须是 tasks.json 里定义的 tasks下的 某一个 label
代码目录结构:
.
├── README.md
├── builds
│ ├── laid.o
│ ├── liblaid.a
│ ├── main.o
│ └── main.o.dSYM
│ └── Contents
│ ├── Info.plist
│ └── Resources
│ └── DWARF
│ └── main.o
├── include
│ └── laid.h
├── laid.code-workspace
└── src
├── laid.c
└── main.c
include/laid.h
内容:
//
// 定义 laid 头文件
//
#include <stdlib.h>
struct laid
{
char *name;
void (* say_hello)(struct laid *l);
char * (* get_name)(struct laid *l);
};
struct laid *create_laid(char *name);
void say_hello(struct laid *l);
char* get_name(struct laid *l);
src/laid.c
内容:
//
// laid 实现文件
//
#include <stdio.h>
#include "laid.h"
void say_hello(struct laid *l) {
printf("Hello: %s", l->name);
}
char* get_name(struct laid *l) {
return l->name;
}
struct laid *create_laid(char *name)
{
struct laid *l = malloc(sizeof(struct laid));
l->name = name;
l->say_hello = say_hello;
l->get_name = get_name;
return l;
}
- 编译 并生成 laid.o 对象文件
/usr/bin/gcc -c -fdiagnostics-color=always -g ~/workspace/bangongyi/golang/la/3rd/laid/src/laid.c -o ~/workspace/bangongyi/golang/la/3rd/laid/builds/laid.o -I ~/workspace/bangongyi/golang/la/3rd/laid/include
- 打包库文件
ar rcs builds/liblaid.a builds/laid.o
golang 里通过cgo 调用
laid-go/linker.go
调用C代码 :
package laid_go
/*
#include "laid.h"
#cgo CFLAGS: -I./../3rd/laid/include
#cgo LDFLAGS: -L./../3rd/laid/builds -llaid
*/
import "C"
import (
"log"
"unsafe"
)
func Laid_print_info(name string) {
l := C.create_laid(C.CString(name))
defer C.free(unsafe.Pointer(l))
log.Println(l.name)
log.Println(C.GoString(l.name))
log.Println(l.say_hello)
log.Println(C.say_hello)
// 这行会报错
// l.say_hello(l)
// laid-go/linker.go:28:2: invalid operation: cannot call non-function l.say_hello (variable of type *[0]byte)
log.Println("'-----'")
s := C.get_name(l)
log.Println(C.GoString(s))
}
main.go 调用写好的
package main
import (
"log"
laid_go "bangongyi.com/la/laid-go"
)
func main() {
laid_go.Laid_print_info("王五")
}
执行结果:
2023/05/14 17:19:23 0x1084000b0
2023/05/14 17:19:23 &[]
2023/05/14 17:19:23 0x1002cf5b0
2023/05/14 17:19:23 '-----'
2023/05/14 17:19:23 王五
笔记:
从 laid_go.Laid_print_info
函数体里测试,发现以下问题:
- C.
${func}
它只能调用 真正的 function, 对于结构体内部的函数指针不能调用,例如:
// l.say_hello(l) 这行会报错
// laid-go/linker.go:28:2: invalid operation: cannot call non-function l.say_hello (variable of type *[0]byte)
- C.
CString(go_string)
将 go_string 转换成 C语言的 字符串指针变量, 所以打印的是地址
- C.
GoString(ptr_c_string)
将 C语言的指针字符串(char *) 转换成 golang string
遗憾
目前对于golang 还处于学习阶段, 对 C.
调用函数指针 没有找到有效方法, 目前能想到能实现的方案是 代理函数
类似:
char* laid_get_name(struct laid * l) {
return l->get_name(l);
}
文末推荐一个有意思的工具: https://revealjs.com/ 网页幻灯片
我是 许一沐
, 请搜索公众号 许一沐
找到我, 共同学习!!!