From 6b623b5ea2a811b54a2391f17081a8981fa733a5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 20 Nov 2019 17:11:07 -0500 Subject: [PATCH] update docs for null terminated stuff --- doc/langref.html.in | 107 +++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 31 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 5ecf312044237c39228ebcb52c76013d31cf0bcd..9215da6cf860862181a2ea8e4a72a37f993dc71c 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -546,7 +546,10 @@ pub fn main() void { {#header_close#} {#header_open|String Literals and Character Literals#}

- String literals are UTF-8 encoded byte arrays. + String literals are single-item constant {#link|Pointers#} to null-terminated UTF-8 encoded byte arrays. + The type of string literals encodes both the length, and the fact that they are null-terminated, + and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and + {#link|Null-Terminated Pointers#}. Dereferencing string literals converts them to {#link|Arrays#}.

Character literals have type {#syntax#}comptime_int{#endsyntax#}, the same as @@ -558,20 +561,15 @@ const assert = @import("std").debug.assert; const mem = @import("std").mem; test "string literals" { - // In Zig a string literal is an array of bytes. - const normal_bytes = "hello"; - assert(@typeOf(normal_bytes) == [5]u8); - assert(normal_bytes.len == 5); - assert(normal_bytes[1] == 'e'); + const bytes = "hello"; + assert(@typeOf(bytes) == *const [5]null u8); + assert(bytes.len == 5); + assert(bytes[1] == 'e'); + assert(bytes[5] == 0); assert('e' == '\x65'); assert('\u{1f4a9}' == 128169); assert('💯' == 128175); assert(mem.eql(u8, "hello", "h\x65llo")); - - // A C string literal is a null terminated pointer. - const null_terminated_bytes = c"hello"; - assert(@typeOf(null_terminated_bytes) == [*]const u8); - assert(null_terminated_bytes[5] == 0); } {#code_end#} {#see_also|Arrays|Zig Test|Source Encoding#} @@ -641,23 +639,6 @@ const hello_world_in_c = \\} ; {#code_end#} -

- For a multiline C string literal, prepend c to each {#syntax#}\\{#endsyntax#}: -

- {#code_begin|syntax#} -const c_string_literal = - c\\#include - c\\ - c\\int main(int argc, char **argv) { - c\\ printf("hello world\n"); - c\\ return 0; - c\\} -; - {#code_end#} -

- In this example the variable {#syntax#}c_string_literal{#endsyntax#} has type {#syntax#}[*]const u8{#endsyntax#} and - has a terminating null byte. -

{#see_also|@embedFile#} {#header_close#} {#header_close#} @@ -1638,12 +1619,11 @@ comptime { assert(message.len == 5); } -// a string literal is an array literal -const same_message = "hello"; +// A string literal is a pointer to an array literal. +const same_message = "hello".*; comptime { assert(mem.eql(u8, message, same_message)); - assert(@typeOf(message) == @typeOf(same_message)); } test "iterate over an array" { @@ -1799,6 +1779,26 @@ test "multidimensional arrays" { } {#code_end#} {#header_close#} + + {#header_open|Null-Terminated Arrays#} +

+ The syntax {#syntax#}[N]null T{#endsyntax#} describes an array which has a null element at the + index corresponding to {#syntax#}len{#endsyntax#}. +

+ {#code_begin|test|null_terminated_array#} +const std = @import("std"); +const assert = std.debug.assert; + +test "null terminated array" { + const array = [_]u8 null {1, 2, 3, 4}; + + assert(@typeOf(array) == [4]null u8); + assert(array.len == 4); + assert(slice[4] == 0); +} + {#code_end#} + {#see_also|Null-Terminated Pointers|Null-Terminated Slices#} + {#header_close#} {#header_close#} {#header_open|Vectors#} @@ -2111,6 +2111,29 @@ test "allowzero" { } {#code_end#} {#header_close#} + + {#header_open|Null-Terminated Pointers#} +

+ The syntax {#syntax#}[*]null T{#endsyntax#} describes a pointer that + has a length determined by a sentinel null value. This provides protection + against buffer overflow and overreads. +

+ {#code_begin|exe_build_err#} +const std = @import("std"); + +// This is also available as `std.c.printf`. +pub extern "c" fn printf(format: [*]null const u8, ...) c_int; + +pub fn main() anyerror!void { + _ = printf("Hello, world!\n"); // OK + + const msg = "Hello, world!\n"; + const non_null_terminated_msg: [msg.len]u8 = msg.*; + _ = printf(&non_null_terminated_msg); +} + {#code_end#} + {#see_also|Null-Terminated Slices|Null-Terminated Arrays#} + {#header_close#} {#header_close#} {#header_open|Slices#} @@ -2194,7 +2217,29 @@ test "slice widening" { } {#code_end#} {#see_also|Pointers|for|Arrays#} + + {#header_open|Null-Terminated Slices#} +

+ The syntax {#syntax#}[]null T{#endsyntax#} is a slice which has a runtime known length + and also guarantees a null value at the element indexed by the length. The type does not + guarantee that there are no null elements before that. Null-terminated slices allow element + access to the {#syntax#}len{#endsyntax#} index. +

+ {#code_begin|test|null_terminated_slice#} +const std = @import("std"); +const assert = std.debug.assert; + +test "null terminated slice" { + const slice: []null const u8 = "hello"; + + assert(slice.len == 5); + assert(slice[5] == 0); +} + {#code_end#} + {#see_also|Null-Terminated Pointers|Null-Terminated Arrays#} {#header_close#} + {#header_close#} + {#header_open|struct#} {#code_begin|test|structs#} // Declare a struct. -- 2.54.0