いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-512 (cgoメモ-08)(C.GoBytes)(Cのバイト列をGoの[]byteへ)

関連記事

Goメモ-502 (cgoメモ-01)(cgoヘッダ) - いろいろ備忘録日記

Goメモ-506 (cgoメモ-02)(cgoヘッダ) - いろいろ備忘録日記

Goメモ-507 (cgoメモ-03)(C.int) - いろいろ備忘録日記

Goメモ-508 (cgoメモ-04)(C言語の構造体) - いろいろ備忘録日記

Goメモ-509 (cgoメモ-05)(C.CString)(Cの文字列) - いろいろ備忘録日記

Goメモ-510 (cgoメモ-06)(C.GoString)(Cの文字列をGoの文字列へ) - いろいろ備忘録日記

Goメモ-511 (cgoメモ-07)(C.CBytes)([]byteをCのバイト列に) - いろいろ備忘録日記

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。

今回から複数回に渡って cgo についてメモしていこうと思います。

cgo は、文字通りGoからCにアクセスすることが出来るようになるものなのですが、とても便利な反面、結構クセが強いのでメモでも残しておかないとすぐ頭から消えてしまいそうだなって思いました。

Cgo is not Go

という格言があったりするので、Go界隈で標準で推奨されていない技術かもしれません。が、実務ではC言語で作成されたライブラリなどは山のようにあります。んで、プロジェクトの方針でGoで作り直すことも出来ない場合も多々あります。そのような場合に非常に便利です。

これからのサンプルは以下のリポジトリにアップしてありますので、良ければご参考ください。

github.com

今回は cgo で利用する C.GoBytes について。

cgo では、import "C" をすることによって、C言語側の型が使えるようになります。

C.GoBytes()は、Cのバイト列をGoのバイトスライスに変換します。渡す際はC側のバイト列を void * つまり unsafe.Pointer で渡します。戻り値は[]byteとなります。

C.CBytes()と違い、Go側でメモリ確保しているので C.free() の呼び出しは必要ありません。

サンプル

main.go

package main

/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const int BUF_SIZE = 15*sizeof(char);

void *buf;

void myAlloc() {
   // MEMO: エラー処理は割愛
   buf = malloc(BUF_SIZE);
   memset(buf, 0, BUF_SIZE);
}

void myAssign() {
   strncpy(buf, "hello C  World", BUF_SIZE);
}

void myPrint() {
   printf("[C ] %s %d\n", (char *)buf, BUF_SIZE);
}

void myFree() {
   free(buf);
}

*/
import "C"
import (
    "encoding/hex"
    "fmt"
    "unsafe"
)

func main() {
    //
    // C側でメモリを確保しバッファにデータを埋める
    //
    C.myAlloc()
    defer C.myFree()

    C.myAssign()
    C.myPrint()

    //
    // Go側の[]byteとして取得
    //
    var (
        cBuf  unsafe.Pointer = C.buf
        goBuf []byte         = C.GoBytes(cBuf, C.BUF_SIZE)
    )

    fmt.Printf("[GO] %s %d\n", string(goBuf), len(goBuf))
    fmt.Printf("[GO] %v\n", hex.Dump(goBuf))
}

Taskfile.yml

# https://taskfile.dev

version: '3'

tasks:
  default:
    cmds:
      - go run main.go

実行

$ task
task: [default] go run main.go
[C ] hello C  World 15
[GO] hello C  World 15
[GO] 00000000  68 65 6c 6c 6f 20 43 20  20 57 6f 72 6c 64 00     |hello C  World.|

参考情報

Goのおすすめ書籍


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。