zig string 周り

に公開

よく?使うものをメモしておく 0.15.2

slice: []const u8

literal

const slice: []const u8 = "abc";
const slice: []const u8 = &.{ 'a', 'b', 'c', 0 };

to pointer

slice.ptr
&slice[0];

c 相互運用

c の関数を呼ぶ

const c = @cImport({
  @cInclude("stdio.h");
});

c.printf("hello");

定義作成

// extern を付けて body の無い関数を作る
// c_int, c_char など明示的に c である型がある。
// i32, u8 とかでもわりと動く。
extern fn hello(ptr: [*c]const u8) void;

hello("world");

c に関数を公開する

// export つける
export fn hello(ptr: [*c]const u8) void
{

}

c の文字列

c_ptr: [*c]u8

というポインタになる。
このポインタ [*c] は zig の [*], [*:0], ?* あたりの特徴を兼ね備えていて

  • nullable
  • index アクセス可
  • sentinel 0 が期待される
  • c_char にせずとも u8 でわりと通る

というような挙動をする。

nullable をはがす

// c_ptr: [*c]const u8
if(c_ptr)|zig_ptr|
{
  // zig_ptr: [*]const u8
}

to slice

const slice: []const u8 = std.mem.span(c_ptr);
// 長さが既知
const slice: []const u8 = c_ptr[0..len];

strlen

const len: usize = std.mem.len(c_ptr);

strcmp

test Strcmp {
    const c_import = @cImport({
        @cInclude("string.h");
    });
    const Tmp = struct {
        fn zigStrcmp(lhs: []const u8, rhs: []const u8) c_int {
            return switch (std.mem.order(u8, lhs, rhs)) {
                .gt => 1,
                .eq => 0,
                .lt => -1,
            };
        }
    };
    {
        const a = "abc";
        const b = "bcd";
        try std.testing.expectEqual(c_import.strcmp(a, b), Tmp.zigStrcmp(a, b));
    }
    {
        const b = "abc";
        const a = "bcd";
        try std.testing.expectEqual(c_import.strcmp(a, b), Tmp.zigStrcmp(a, b));
    }
    {
        const a = "abc";
        const b = "abc";
        try std.testing.expectEqual(c_import.strcmp(a, b), Tmp.zigStrcmp(a, b));
    }
}

va_list

        var ap = @cVaStart();
        defer @cVaEnd(&ap);
        _ = c.vsprintf(buf, fmt, @ptrCast(&ap));

Discussion