Commit 6b623b5ea2

Andrew Kelley <andrew@ziglang.org>
2019-11-20 23:11:07
update docs for null terminated stuff
1 parent fd6020c
Changed files (1)
doc/langref.html.in
@@ -546,7 +546,10 @@ pub fn main() void {
       {#header_close#}
       {#header_open|String Literals and Character Literals#}
       <p>
-      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#}.
       </p>
       <p>
       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#}
-      <p>
-      For a multiline C string literal, prepend <code>c</code> to each {#syntax#}\\{#endsyntax#}:
-      </p>
-      {#code_begin|syntax#}
-const c_string_literal =
-    c\\#include <stdio.h>
-    c\\
-    c\\int main(int argc, char **argv) {
-    c\\    printf("hello world\n");
-    c\\    return 0;
-    c\\}
-;
-      {#code_end#}
-      <p>
-      In this example the variable {#syntax#}c_string_literal{#endsyntax#} has type {#syntax#}[*]const u8{#endsyntax#} and
-      has a terminating null byte.
-      </p>
       {#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#}
+      <p>
+      The syntax {#syntax#}[N]null T{#endsyntax#} describes an array which has a null element at the
+      index corresponding to {#syntax#}len{#endsyntax#}.
+      </p>
+      {#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#}
+      <p>
+      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.
+      </p>
+      {#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#}
+      <p>
+      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.
+      </p>
+      {#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.