Prometheus, Grafana, Influxdbを使ってみてGo言語で実装されているということから、C言語とのインターフェイスを調べてみました。
環境)
$go version
go version go1.20.4 linux/amd64
参考)
https://ja.wikibooks.org/wiki/Go/cgo%E3%81%A7Go%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89C%E3%81%AE%E9%96%A2%E6%95%B0%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B
https://schima.hatenablog.com/entry/20100523/1274620423
https://karthikkaranth.me/blog/calling-c-code-from-go/
hello.c
1 2 3 4 |
void hello() { printf("hello!\n"); } |
callc.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package main import ( /* #include <stdio.h> #include <stdlib.h> #include "hello.c" int add(int a, int b){ return a+b; } */ "C" "unsafe" "fmt" ) func div(n, d int) (int, int){ divmode := C.div(C.int(n), C.int(d)) return int(divmode.quot), int(divmode.rem) } func main(){ C.hello(); fmt.Printf("add: %d\n", C.add(1,2)) p := C.CString("abcdefg") defer C.free(unsafe.Pointer(p)) C.puts(p) for i := 0; i<5; i++ { quot, rem :=div(i, 3) fmt.Printf("%d / 3: %v .. %v\n", i, quot, rem) } } |
上記Go言語からC言語を呼び出していますが、とても簡単に記述できることにおどろかされました。(コメント内に記述)
ここでは言葉での説明よりコードを書いた方が理解しやすいため、いろんな呼び出し方を併記しました。
実行結果
$ go run callc.go
hello!
add: 3
abcdefg
0 / 3: 0 .. 0
1 / 3: 0 .. 1
2 / 3: 0 .. 2
3 / 3: 1 .. 0
4 / 3: 1 .. 1
今度は逆に、CからGoの関数を呼び出してみました。
gofunc.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package main import( "C" "fmt" ) //export add func add(a int, b int) int { return a + b } func main(){ fmt.Printf("%d + %d = %d\n", 1, 2, add(1,2)) } |
1 2 3 4 5 6 7 8 9 |
#include<stdio.h> #include"gofunc.h" int main() { GoInt a = 1, b=2; printf("%d + %d = %d\n", (int)a, (int)b, (int)add(a,b)); } |
ビルド
go build -buildmode=c-archive gofunc.go
gcc -o callgo callgo.c gofunc.a -lpthread
gofunc.h(自動生成)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* Code generated by cmd/cgo; DO NOT EDIT. */ /* package command-line-arguments */ #line 1 "cgo-builtin-export-prolog" #include <stddef.h> --中略-- typedef signed char GoInt8; typedef unsigned char GoUint8; typedef short GoInt16; typedef unsigned short GoUint16; typedef int GoInt32; typedef unsigned int GoUint32; --中略-- extern GoInt add(GoInt a, GoInt b); |
実行結果
$ ./callgo
1 + 2 = 3
Go言語のコードは、バイナリーコンパイル実行もできるため、C言語とのリンクも容易です。
いざというときのためのメモでした。