Files
test/guide/language/sentinel-termination.zig
2026-01-19 05:43:29 +09:00

79 lines
2.7 KiB
Zig

const expect = @import("std").testing.expect;
// Arrays, slices and many pointers may be terminated by a value of their child type.
// This is known as sentinel termination. These follow the syntax `[N:t]T`, `[:t]T`, and `[*:t]T`,
// where `t` is a value of the child type `T`.
// An example of a sentinel terminated array. The built-in `@ptrCast` is used to perform an unsafe type conversion.
// This shows us that the last element of the array is followed by a 0 byte.
test "sentinel termination" {
const terminated = [3:0]u8{ 3, 2, 1 };
try expect(terminated.len == 3);
try expect(@as(*const [4]u8, @ptrCast(&terminated))[3] == 0);
}
// The types of string literals is `*const [N:0]u8`, where N is the length of the string.
// This allows string literals to coerce to sentinel terminated slices, and sentinel terminated many pointers.
// Note: string literals are UTF-8 encoded.
test "string literal" {
try expect(@TypeOf("hello") == *const [5:0]u8);
}
// `[*:0]u8` and `[*:0]const u8` perfectly model C's strings.
const eql = @import("std").mem.eql;
test "C string" {
const c_string: [*:0]const u8 = "hello";
var array: [5]u8 = undefined;
var i: usize = 0;
while (c_string[i] != 0) : (i += 1) {
array[i] = c_string[i];
}
// XXX: Maybe we should use `c_string[0..i]` instead of `c_string[0..5]`?
// try expect(eql(u8, &array, c_string[0..i]));
}
// Sentinel terminated types coerce to their non-sentinel-terminated counterparts.
test "coercion" {
const a: [*:0]u8 = undefined;
const b: [*]u8 = a;
const c: [5:0]u8 = undefined;
const d: [5]u8 = c;
const e: [:0]f32 = undefined;
const f: []f32 = e;
_ = .{ b, d, f }; //ignore unused
}
// Sentinel terminated slicing is provided
// which can be used to create a sentinel terminated slice with the syntax `x[n..m:t]`,
// where `t` is the terminator value.
// Doing this is an assertion from the programmer that the memory is terminated where it should be
// - getting this wrong is detectable illegal behaviour.
test "sentinel terminated slicing" {
var x = [_:0]u8{255} ** 3;
const y = x[0..3 :0];
_ = y;
}
// My tests here to understand the concept better
const print = @import("std").debug.print;
test "sentianel checking" {
const x = [_:0]u8{ 'h', 'i', @as(u8, 0), 'w', 'o', 'r', 'l', 'd', @as(u8, 0) };
// To validate the memory is terminated where it should be, we can use the `x[n..m:t]` syntax,
const y = x[0..2 :@as(u8, 0)];
// print("\n", .{});
// print("x: {any}\n", .{x});
// print("y: {any}\n", .{y});
try expect(x[2] == 0);
try expect(y.len == 2);
try expect(y[0] == 'h');
try expect(y[1] == 'i');
try expect(y[2] == 0);
}