TechCraft – エンジニアのためのスキルアップメモ

エンジニアのスキルアップを少しでも加速する技術ブログ

【脱・C言語】Zig入門

Rustよりもシンプルで、Cよりも安全な「第三の選択肢」を徹底解説

「C言語は古すぎるが、Rustは学習コストが高すぎる...」 「もっとシンプルに、でも低レイヤーを完全に制御したい」 そんなエンジニアの心の隙間を埋める言語として、Zig(ジグ) が爆発的な人気を集めているのをご存知でしょうか? 2026年現在、Zigは単なる「実験的な言語」の枠を超え、Bun(超高速JSランタイム)やTigerBeetle(金融系データベース)など、パフォーマンスが命のプロジェクトで採用が進んでいます。

今回は、「可能性に有り余る言語」 と呼ばれるZigの魅力と、実際に手を動かして感じるその「手触り」を徹底解説します。


1. なぜ今、Zigなのか?(3つの革命)

Zigは、Andrew Kelley氏によって開発されたシステムプログラミング言語です。その哲学は驚くほど明確です。

① 「隠された挙動」が一切ない

C++やRustでは、演算子オーバーロードやコンストラクタ、デストラクタなど、コードを見ただけでは分からない処理が裏で走ることがあります。 Zigにはそれがありません。 * 隠れた制御フローなし: マクロや演算子オーバーロードが存在しない。 * 隠れたメモリ割り当てなし: ヒープメモリを使う場合は、必ず「アロケータ(Allocator)」を明示的に渡す必要があります。

「コードに書いてあることだけが実行される」。この安心感が、堅牢なシステムを作る鍵です。

② C言語との「完全な」相互運用性

他の言語(RustやGo)からCのライブラリを呼ぶには、FFI(Foreign Function Interface)というバインディングを書く必要があり、これが非常に面倒でした。 ZigはC言語のヘッダーファイル(.h)を直接インポートできます。 しかも、ZigのコンパイラはCコンパイラとしても機能します(zig ccコマンド)。既存のCプロジェクトをZigコンパイラでビルドするだけで、クロスコンパイル環境が手に入るのです。

③ 魔法のような「Comptime」

Zig最大の発明と言われるのが Comptime(コンパイル時実行) です。 ジェネリクスやマクロのような複雑な構文を覚える必要はありません。「コンパイル時に普通のZigコードを実行する」だけで、型生成や最適化ができてしまいます。これは一度体験すると戻れない便利さです。


2. 環境構築

Zigの環境構築は非常にシンプルです。インストーラーすら不要な場合がほとんどです。

インストール手順

公式の ダウンロードページ からバイナリを取得するか、パッケージマネージャーを使用します。

Mac (Homebrew)

brew install zig

Windows (winget)

winget install zig.zig

Linux / macOS (Version Manager) バージョン管理ツールの zvm (Zig Version Manager) を使うのが現在は主流です。

# zvmのインストール(例)
curl -L [https://github.com/tristanisham/zvm/releases/download/v0.7.0/install.sh](https://github.com/tristanisham/zvm/releases/download/v0.7.0/install.sh) | sh
zvm install master
zvm use master

インストール後、以下のコマンドでバージョンを確認しましょう。

zig version
# 出力例: 0.15.2 (2026年1月時点の最新安定版を想定)

VS Codeの設定 拡張機能「Zig Language」をインストールしてください。 また、LSP(Language Server Protocol)である ZLS を導入すると、補完や定義ジャンプが効くようになり、開発体験が劇的に向上します。


3. 実践・ハンズオン:Zigの「手触り」を知る

それでは、実際にコードを書いてみましょう。 プロジェクト用のディレクトリを作成し、初期化します。

mkdir zig-demo
cd zig-demo
zig init

これで build.zig や src/main.zig が生成されます。

ステップ1: Hello Worldと「テスト」

Zigはテスト機能が言語に組み込まれています。src/main.zig を以下のように書き換えてみましょう。

const std = @import("std");

pub fn main() !void {
    // 標準出力の取得
    const stdout = std.io.getStdOut().writer();
    
    // try はエラーハンドリング(失敗したらエラーを上に投げる)
    try stdout.print("Hello, {s}!\n", .{"TechCraft Reader"});
}

// テストコードを同じファイルに書ける
test "simple test" {
    const expected = 5;
    const actual = 2 + 3;
    try std.testing.expect(actual == expected);
}

実行:

zig build run

テスト実行:

zig test src/main.zig

ステップ2: メモリ管理の「明示」

ここがZigの真骨頂です。動的にメモリを確保する場合、Zigでは「どの種類のメモリ管理(アロケータ)を使うか」をプログラマが選びます。

const std = @import("std");

pub fn main() !void {
    // 汎用アロケータ(General Purpose Allocator)の初期化
    // メモリリークを検知する機能がついている
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    
    // スコープを抜けるときにdeinit(解放)を実行
    defer _ = gpa.deinit(); 
    
    const allocator = gpa.allocator();

    // 動的配列(ArrayList)の作成
    var list = std.ArrayList(i32).init(allocator);
    
    // ここで defer を使うことで、main関数終了時の解放を予約
    // C言語のような free 忘れを防げる!
    defer list.deinit();

    // データの追加
    try list.append(10);
    try list.append(20);
    try list.append(42);

    const stdout = std.io.getStdOut().writer();
    try stdout.print("List content: {any}\n", .{list.items});
}

ポイント: * defer: 「このブロックを抜ける時に必ず実行する」という予約語。Go言語にもありますが、リソース管理において最強の武器です。 * allocator: 関数が隠れてメモリ確保するのを防ぐため、メモリが必要な関数には必ず引数として allocator を渡します。これにより「どこでメモリが確保されているか」が一目瞭然になります。

ステップ3: C言語の関数を直接呼ぶ

ZigがいかにC言語と仲が良いかを見てみましょう。Cの標準ライブラリ time.h を使ってみます。

const std = @import("std");
// C言語のライブラリをインポート
const c = @cImport({
    @cInclude("time.h");
    @cInclude("stdio.h");
});

pub fn main() !void {
    // Cのtime関数を呼び出し
    const current_time = c.time(null);
    
    // Cのprintf関数を呼び出し(Zigから直接!)
    _ = c.printf("Current Timestamp from C: %ld\n", current_time);
    
    // もちろんZigの標準出力も使える
    const stdout = std.io.getStdOut().writer();
    try stdout.print("Timestamp via Zig: {d}\n", .{current_time});
}

特別なバインディング生成ツールは不要です。ただ @cImport するだけ。これがZigが「Cの後継」と言われる所以です。


4. トラブルシューティング:初心者がハマるポイント

Q. 文字列の扱いが難しいのですが?

A. Zigには「String型」という特別な型はありません。文字列は単なるバイトの配列([]u8)または、NULL終端されたポインタ([*:0]u8)です。 最初は戸惑いますが、「メモリ上でどうデータが並んでいるか」を意識できるようになると、無駄なコピーを避けた高速な処理が書けるようになります。

Q. コンパイルエラー "unused variable" がうるさい

A. Zigは「使われていない変数」をコンパイルエラーにします。デバッグ中に一時的に変数を残したい場合は、_ = my_var; と書いて、「意図的に捨てている」ことをコンパイラに伝えてください。

Q. バージョンによる破壊的変更が多い

A. Zigはまだバージョン1.0に達していません。ネット上の古い記事(0.9系や0.11系)のコードは動かないことがよくあります。 エラーが出たら、まずは公式ドキュメント(ziglang.org/documentation/)の最新版を確認するか、ziglings(後述)で最新の構文を学ぶのが近道です。


5. まとめ:Zigは学ぶ価値があるか?

結論から言えば、YES です。

  • 低レイヤーの理解が深まる: メモリ管理やポインタの仕組みが、C言語よりも安全に、かつRustよりも素直に理解できます。
  • ツールチェーンとして優秀: Zig言語自体を書かなくても、zig cc は強力なC/C++クロスコンパイラとして使えます。
  • 将来性: インフラ、データベース、ゲームエンジンなど、パフォーマンスが要求される分野での採用が加速しています。

Next Step: まずは、Zigの構文をクイズ形式で学べる Ziglings に挑戦してみてください。壊れたコードを直していく形式で、ゲーム感覚でZigをマスターできます。

C言語の複雑さに疲れた方、Rustの所有権システムで挫折した方。 Zigという「シンプルで強力な道具」を、あなたのツールボックスに加えてみませんか?


6. 参考文献・リンク