いろいろ備忘録日記

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

Goメモ-509 (cgoメモ-05)(C.CString)(Cの文字列)

関連記事

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

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

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

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

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

概要

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

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

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

Cgo is not Go

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

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

github.com

今回は cgo で利用する C言語の文字列 というか char * について。

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

C言語側の文字列をcgoにて利用する場合は、C.CString を利用します。 C.CString は、内部で malloc() によりヒープメモリを確保しているため 利用後に必ず C.free() にてメモリを開放する必要があります。当然、C.free() を利用するためには <stdlib.h> のインクルードが必要です。

C.CString は、C言語の (char *) を表します。

サンプル

main.go

package main

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

void pStr(const char *m) {
   printf("%s\n", m);
}
*/
import "C"
import (
    "fmt"
    "unsafe"
)

func main() {
    //
    // cgoにてC言語側の文字列を扱いたい場合は
    // C.CStringを利用する。
    //
    // C.CStringは、内部でmallocを使ってヒープメモリを
    // 確保しているため、利用後は必ず C.free() にてメモリを開放する必要がある。
    //
    // C.CStringは、C言語の世界の (char *) を表す。
    // (unsafe.Pointer() は、C言語の世界の (void *) を表す)
    //
    var (
        goStr = "this is go string"
        cStr  = C.CString(goStr)
    )

    // 必ず C.free() で開放する
    defer C.free(unsafe.Pointer(cStr))

    fmt.Printf("%[1]v (%[1]T)\n", goStr)
    fmt.Printf("%[1]v (%[1]T)\n", cStr)
    C.pStr(cStr)
}

Taskfile.yml

# https://taskfile.dev

version: '3'

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

実行

$ task
task: [default] go run main.go
this is go string (string)
0x15e1140 (*main._Ctype_char)
this is go string

参考情報

Goのおすすめ書籍


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

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