Function zeroes [src]

Generally, Zig users are encouraged to explicitly initialize all fields of a struct explicitly rather than using this function. However, it is recognized that there are sometimes use cases for initializing all fields to a "zero" value. For example, when interfacing with a C API where this practice is more common and relied upon. If you are performing code review and see this function used, examine closely - it may be a code smell. Zero initializes the type. This can be used to zero-initialize any type for which it makes sense. Structs will be initialized recursively.

Prototype

pub fn zeroes(comptime T: type) T

Parameters

T: type

Example

test zeroes { const C_struct = extern struct { x: u32, y: u32 align(128), }; var a = zeroes(C_struct); // Extern structs should have padding zeroed out. try testing.expectEqualSlices(u8, &[_]u8{0} ** @sizeOf(@TypeOf(a)), asBytes(&a)); a.y += 10; try testing.expect(a.x == 0); try testing.expect(a.y == 10); const ZigStruct = struct { comptime comptime_field: u8 = 5, integral_types: struct { integer_0: i0, integer_8: i8, integer_16: i16, integer_32: i32, integer_64: i64, integer_128: i128, unsigned_0: u0, unsigned_8: u8, unsigned_16: u16, unsigned_32: u32, unsigned_64: u64, unsigned_128: u128, float_32: f32, float_64: f64, }, pointers: struct { optional: ?*u8, c_pointer: [*c]u8, slice: []u8, nullTerminatedString: [:0]const u8, }, array: [2]u32, vector_u32: @Vector(2, u32), vector_f32: @Vector(2, f32), vector_bool: @Vector(2, bool), optional_int: ?u8, empty: void, sentinel: [3:0]u8, }; const b = zeroes(ZigStruct); try testing.expectEqual(@as(u8, 5), b.comptime_field); try testing.expectEqual(@as(i8, 0), b.integral_types.integer_0); try testing.expectEqual(@as(i8, 0), b.integral_types.integer_8); try testing.expectEqual(@as(i16, 0), b.integral_types.integer_16); try testing.expectEqual(@as(i32, 0), b.integral_types.integer_32); try testing.expectEqual(@as(i64, 0), b.integral_types.integer_64); try testing.expectEqual(@as(i128, 0), b.integral_types.integer_128); try testing.expectEqual(@as(u8, 0), b.integral_types.unsigned_0); try testing.expectEqual(@as(u8, 0), b.integral_types.unsigned_8); try testing.expectEqual(@as(u16, 0), b.integral_types.unsigned_16); try testing.expectEqual(@as(u32, 0), b.integral_types.unsigned_32); try testing.expectEqual(@as(u64, 0), b.integral_types.unsigned_64); try testing.expectEqual(@as(u128, 0), b.integral_types.unsigned_128); try testing.expectEqual(@as(f32, 0), b.integral_types.float_32); try testing.expectEqual(@as(f64, 0), b.integral_types.float_64); try testing.expectEqual(@as(?*u8, null), b.pointers.optional); try testing.expectEqual(@as([*c]u8, null), b.pointers.c_pointer); try testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice); try testing.expectEqual(@as([:0]const u8, ""), b.pointers.nullTerminatedString); for (b.array) |e| { try testing.expectEqual(@as(u32, 0), e); } try testing.expectEqual(@as(@TypeOf(b.vector_u32), @splat(0)), b.vector_u32); try testing.expectEqual(@as(@TypeOf(b.vector_f32), @splat(0.0)), b.vector_f32); try testing.expectEqual(@as(@TypeOf(b.vector_bool), @splat(false)), b.vector_bool); try testing.expectEqual(@as(?u8, null), b.optional_int); for (b.sentinel) |e| { try testing.expectEqual(@as(u8, 0), e); } const C_union = extern union { a: u8, b: u32, }; const c = zeroes(C_union); try testing.expectEqual(@as(u8, 0), c.a); try testing.expectEqual(@as(u32, 0), c.b); const comptime_union = comptime zeroes(C_union); try testing.expectEqual(@as(u8, 0), comptime_union.a); try testing.expectEqual(@as(u32, 0), comptime_union.b); // Ensure zero sized struct with fields is initialized correctly. _ = zeroes(struct { handle: void }); }

Source

pub fn zeroes(comptime T: type) T { switch (@typeInfo(T)) { .comptime_int, .int, .comptime_float, .float => { return @as(T, 0); }, .@"enum" => { return @as(T, @enumFromInt(0)); }, .void => { return {}; }, .bool => { return false; }, .optional, .null => { return null; }, .@"struct" => |struct_info| { if (@sizeOf(T) == 0) return undefined; if (struct_info.layout == .@"extern") { var item: T = undefined; @memset(asBytes(&item), 0); return item; } else { var structure: T = undefined; inline for (struct_info.fields) |field| { if (!field.is_comptime) { @field(structure, field.name) = zeroes(field.type); } } return structure; } }, .pointer => |ptr_info| { switch (ptr_info.size) { .slice => { if (ptr_info.sentinel()) |sentinel| { if (ptr_info.child == u8 and sentinel == 0) { return ""; // A special case for the most common use-case: null-terminated strings. } @compileError("Can't set a sentinel slice to zero. This would require allocating memory."); } else { return &[_]ptr_info.child{}; } }, .c => { return null; }, .one, .many => { if (ptr_info.is_allowzero) return @ptrFromInt(0); @compileError("Only nullable and allowzero pointers can be set to zero."); }, } }, .array => |info| { return @splat(zeroes(info.child)); }, .vector => |info| { return @splat(zeroes(info.child)); }, .@"union" => |info| { if (info.layout == .@"extern") { var item: T = undefined; @memset(asBytes(&item), 0); return item; } @compileError("Can't set a " ++ @typeName(T) ++ " to zero."); }, .enum_literal, .error_union, .error_set, .@"fn", .type, .noreturn, .undefined, .@"opaque", .frame, .@"anyframe", => { @compileError("Can't set a " ++ @typeName(T) ++ " to zero."); }, } }