laid: 一次 CGO 學(xué)習(xí)之旅

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í)!!!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坟冲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子窃诉,更是在濱河造成了極大的恐慌乐纸,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲤氢,死亡現(xiàn)場離奇詭異搀擂,居然都是意外死亡西潘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門哨颂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來喷市,“玉大人,你說我怎么就攤上這事威恼∑沸眨” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵箫措,是天一觀的道長腹备。 經(jīng)常有香客問我,道長斤蔓,這世上最難降的妖魔是什么植酥? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮附迷,結(jié)果婚禮上惧互,老公的妹妹穿的比我還像新娘。我一直安慰自己喇伯,他們只是感情好喊儡,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著稻据,像睡著了一般艾猜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捻悯,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天匆赃,我揣著相機與錄音,去河邊找鬼今缚。 笑死算柳,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的姓言。 我是一名探鬼主播瞬项,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼何荚!你這毒婦竟也來了囱淋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤餐塘,失蹤者是張志新(化名)和其女友劉穎妥衣,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡税手,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年蜂筹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芦倒。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡狂票,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出熙暴,到底是詐尸還是另有隱情,我是刑警寧澤慌盯,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布周霉,位于F島的核電站,受9級特大地震影響亚皂,放射性物質(zhì)發(fā)生泄漏俱箱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一灭必、第九天 我趴在偏房一處隱蔽的房頂上張望狞谱。 院中可真熱鬧,春花似錦禁漓、人聲如沸跟衅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伶跷。三九已至,卻和暖如春秘狞,著一層夾襖步出監(jiān)牢的瞬間叭莫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工烁试, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留雇初,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓减响,卻偏偏與公主長得像靖诗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辩蛋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • Runtime 簡介和發(fā)展 Runtime 簡介 Golang Runtime 是go語言運行所需要的基礎(chǔ)設(shè)施 協(xié)...
    LegendGo閱讀 1,426評論 0 2
  • 目錄 統(tǒng)一規(guī)范篇 命名篇 開發(fā)篇 優(yōu)化篇 統(tǒng)一規(guī)范篇 本篇主要描述了公司內(nèi)部同事都必須遵守的一些開發(fā)規(guī)矩呻畸,如統(tǒng)一開...
    零一間閱讀 1,905評論 0 2
  • 環(huán)境搭建 Golang在Mac OS上的環(huán)境配置 使用Visual Studio Code輔助Go源碼編寫 VS ...
    隕石墜滅閱讀 5,772評論 0 5
  • 編寫和優(yōu)化Go代碼 本文檔概述了編寫高性能Go代碼的最佳實踐。 雖然有些討論會提高單個服務(wù)的速度(通過緩存等)悼院,但...
    freelang閱讀 2,214評論 0 4
  • django+celery+psutil+channels+elasticsearch實現(xiàn)監(jiān)控實時告警功能--一次...
    zhaojian821閱讀 2,721評論 0 2