laid
是一個 cgo 的測試用例
使用下面實例 完成 cgo 庫的學(xué)習(xí)
VS Code 配置
工作區(qū)
配置
- 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": "調(diào)試器生成的任務(wù)彭雾。"
}
],
"version": "2.0.0"
}
- launch.json
配置 調(diào)試工具
{
// 使用 IntelliSense 了解相關(guān)屬性嫂用。
// 懸停以查看現(xiàn)有屬性的描述亏吝。
// 欲了解更多信息,請訪問: 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
代碼目錄結(jié)構(gòu):
.
├── 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
內(nèi)容:
//
// 定義 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
內(nèi)容:
//
// laid 實現(xiàn)文件
//
#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 調(diào)用
laid-go/linker.go
調(diào)用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 調(diào)用寫好的
package main
import (
"log"
laid_go "bangongyi.com/la/laid-go"
)
func main() {
laid_go.Laid_print_info("王五")
}
執(zhí)行結(jié)果:
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
函數(shù)體里測試,發(fā)現(xiàn)以下問題:
- C.
${func}
它只能調(diào)用 真正的 function, 對于結(jié)構(gòu)體內(nèi)部的函數(shù)指針不能調(diào)用,例如:
// 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 轉(zhuǎn)換成 C語言的 字符串指針變量, 所以打印的是地址
- C.
GoString(ptr_c_string)
將 C語言的指針字符串(char *) 轉(zhuǎn)換成 golang string
遺憾
目前對于golang 還處于學(xué)習(xí)階段, 對 C.
調(diào)用函數(shù)指針 沒有找到有效方法, 目前能想到能實現(xiàn)的方案是 代理函數(shù)
類似:
char* laid_get_name(struct laid * l) {
return l->get_name(l);
}
文末推薦一個有意思的工具: https://revealjs.com/ 網(wǎng)頁幻燈片
我是 許一沐
, 請搜索公眾號 許一沐
找到我, 共同學(xué)習(xí)!!!