cgo を使ってみます
cgo って何?という時にここを読むと良さそうです!
コードを書いてみる
cgo では C.C言語の関数()
とすることで, C言語から関数を呼び出すことができます. 実際に簡単な print を行うコードを書いてみます. ちなみに OS は Mac OSX 10.11.6 です.
package main /* #include <stdio.h> void print(const char *str) { printf("%s", str); } */ import "C" func main() { str := C.CString("Hello, World\n") C.print(str) }
出力結果は
Hello, World
となります. 始め
C.printf(C.CString("Hello, World\n"))
という風に書いてましたが, unexpected type: ...
というエラーが出てコンパイルができませんでした. これは僕の予想ですが, printf(1)
の引数は次のようになっているからだと考えました.
int printf(const char * __restrict, ...)
事実はわからないので, 知ってる方教えて欲しいです.
C で得られた結果を Go で扱ってみる
package main /* package main /* #include <string.h> int num(int n) { return 10 + n; } float flt(float f) { return f + 20.5; } char *str(char *s) { return strcat(s, " Good!!"); } */ import "C" import "fmt" func main() { n := C.num(10) fmt.Println(n) f := C.flt(20.78) fmt.Println(f) s := C.str(C.CString("Condition is")) fmt.Println(C.GoString(s)) }
得られた出力結果です.
20 41.28 Condition is Good!!
結構簡単にやり取りできますが, C で扱う文字列と Go で扱う文字列は型が異なるため, C.GoString
を利用して C 側で得られた文字列の結果を Go の文字列へ変換してあげることがポイントです.
Go から C の Macro を呼び出してみる
Macro に文字列, をしていしてる場合は次のように Go の文字列として扱うことができるようです.
package main /* #define Hello "Hello" #define INT 10 #define CHR 'A' */ import "C" import "fmt" func main() { fmt.Println(C.Hello, C.INT, C.CHR) }
結果は次のようになります.
Hello 10 65
しかし, まだ対応してないのか #define FLOAT 1.234
のような Macro を呼び出そうとするとエラーになります.
C の errno を Go の error として扱う
cgo のドキュメントには次のような記述があります.
Any C function (even void functions) may be called in a multiple assignment context to retrieve both the return value (if any) and the C errno variable as an error (use _ to skip the result value if the function returns void).
試してみましょう.
package main /* #include <math.h> */ import "C" import ( "fmt" "log" ) func main() { n, err := C.sqrt(-1) //n, err := C.sqrt(4) if err != nil { log.Fatal(err.Error()) } fmt.Println(n) }
結果は
NaN
ちゃんとエラーを得ることができているみたいですね!