Skip to content

Commit 974e44b

Browse files
committed
update docs for null terminated stuff
1 parent 8f59665 commit 974e44b

File tree

1 file changed

+76
-31
lines changed

1 file changed

+76
-31
lines changed

doc/langref.html.in

Lines changed: 76 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,10 @@ pub fn main() void {
546546
{#header_close#}
547547
{#header_open|String Literals and Character Literals#}
548548
<p>
549-
String literals are UTF-8 encoded byte arrays.
549+
String literals are single-item constant {#link|Pointers#} to null-terminated UTF-8 encoded byte arrays.
550+
The type of string literals encodes both the length, and the fact that they are null-terminated,
551+
and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and
552+
{#link|Null-Terminated Pointers#}. Dereferencing string literals converts them to {#link|Arrays#}.
550553
</p>
551554
<p>
552555
Character literals have type {#syntax#}comptime_int{#endsyntax#}, the same as
@@ -558,20 +561,15 @@ const assert = @import("std").debug.assert;
558561
const mem = @import("std").mem;
559562

560563
test "string literals" {
561-
// In Zig a string literal is an array of bytes.
562-
const normal_bytes = "hello";
563-
assert(@typeOf(normal_bytes) == [5]u8);
564-
assert(normal_bytes.len == 5);
565-
assert(normal_bytes[1] == 'e');
564+
const bytes = "hello";
565+
assert(@typeOf(bytes) == *const [5]null u8);
566+
assert(bytes.len == 5);
567+
assert(bytes[1] == 'e');
568+
assert(bytes[5] == 0);
566569
assert('e' == '\x65');
567570
assert('\u{1f4a9}' == 128169);
568571
assert('💯' == 128175);
569572
assert(mem.eql(u8, "hello", "h\x65llo"));
570-
571-
// A C string literal is a null terminated pointer.
572-
const null_terminated_bytes = c"hello";
573-
assert(@typeOf(null_terminated_bytes) == [*]const u8);
574-
assert(null_terminated_bytes[5] == 0);
575573
}
576574
{#code_end#}
577575
{#see_also|Arrays|Zig Test|Source Encoding#}
@@ -641,23 +639,6 @@ const hello_world_in_c =
641639
\\}
642640
;
643641
{#code_end#}
644-
<p>
645-
For a multiline C string literal, prepend <code>c</code> to each {#syntax#}\\{#endsyntax#}:
646-
</p>
647-
{#code_begin|syntax#}
648-
const c_string_literal =
649-
c\\#include <stdio.h>
650-
c\\
651-
c\\int main(int argc, char **argv) {
652-
c\\ printf("hello world\n");
653-
c\\ return 0;
654-
c\\}
655-
;
656-
{#code_end#}
657-
<p>
658-
In this example the variable {#syntax#}c_string_literal{#endsyntax#} has type {#syntax#}[*]const u8{#endsyntax#} and
659-
has a terminating null byte.
660-
</p>
661642
{#see_also|@embedFile#}
662643
{#header_close#}
663644
{#header_close#}
@@ -1638,12 +1619,11 @@ comptime {
16381619
assert(message.len == 5);
16391620
}
16401621

1641-
// a string literal is an array literal
1642-
const same_message = "hello";
1622+
// A string literal is a pointer to an array literal.
1623+
const same_message = "hello".*;
16431624

16441625
comptime {
16451626
assert(mem.eql(u8, message, same_message));
1646-
assert(@typeOf(message) == @typeOf(same_message));
16471627
}
16481628

16491629
test "iterate over an array" {
@@ -1799,6 +1779,26 @@ test "multidimensional arrays" {
17991779
}
18001780
{#code_end#}
18011781
{#header_close#}
1782+
1783+
{#header_open|Null-Terminated Arrays#}
1784+
<p>
1785+
The syntax {#syntax#}[N]null T{#endsyntax#} describes an array which has a null element at the
1786+
index corresponding to {#syntax#}len{#endsyntax#}.
1787+
</p>
1788+
{#code_begin|test|null_terminated_array#}
1789+
const std = @import("std");
1790+
const assert = std.debug.assert;
1791+
1792+
test "null terminated array" {
1793+
const array = [_]u8 null {1, 2, 3, 4};
1794+
1795+
assert(@typeOf(array) == [4]null u8);
1796+
assert(array.len == 4);
1797+
assert(slice[4] == 0);
1798+
}
1799+
{#code_end#}
1800+
{#see_also|Null-Terminated Pointers|Null-Terminated Slices#}
1801+
{#header_close#}
18021802
{#header_close#}
18031803

18041804
{#header_open|Vectors#}
@@ -2111,6 +2111,29 @@ test "allowzero" {
21112111
}
21122112
{#code_end#}
21132113
{#header_close#}
2114+
2115+
{#header_open|Null-Terminated Pointers#}
2116+
<p>
2117+
The syntax {#syntax#}[*]null T{#endsyntax#} describes a pointer that
2118+
has a length determined by a sentinel null value. This provides protection
2119+
against buffer overflow and overreads.
2120+
</p>
2121+
{#code_begin|exe_build_err#}
2122+
const std = @import("std");
2123+
2124+
// This is also available as `std.c.printf`.
2125+
pub extern "c" fn printf(format: [*]null const u8, ...) c_int;
2126+
2127+
pub fn main() anyerror!void {
2128+
_ = printf("Hello, world!\n"); // OK
2129+
2130+
const msg = "Hello, world!\n";
2131+
const non_null_terminated_msg: [msg.len]u8 = msg.*;
2132+
_ = printf(&non_null_terminated_msg);
2133+
}
2134+
{#code_end#}
2135+
{#see_also|Null-Terminated Slices|Null-Terminated Arrays#}
2136+
{#header_close#}
21142137
{#header_close#}
21152138

21162139
{#header_open|Slices#}
@@ -2194,7 +2217,29 @@ test "slice widening" {
21942217
}
21952218
{#code_end#}
21962219
{#see_also|Pointers|for|Arrays#}
2220+
2221+
{#header_open|Null-Terminated Slices#}
2222+
<p>
2223+
The syntax {#syntax#}[]null T{#endsyntax#} is a slice which has a runtime known length
2224+
and also guarantees a null value at the element indexed by the length. The type does not
2225+
guarantee that there are no null elements before that. Null-terminated slices allow element
2226+
access to the {#syntax#}len{#endsyntax#} index.
2227+
</p>
2228+
{#code_begin|test|null_terminated_slice#}
2229+
const std = @import("std");
2230+
const assert = std.debug.assert;
2231+
2232+
test "null terminated slice" {
2233+
const slice: []null const u8 = "hello";
2234+
2235+
assert(slice.len == 5);
2236+
assert(slice[5] == 0);
2237+
}
2238+
{#code_end#}
2239+
{#see_also|Null-Terminated Pointers|Null-Terminated Arrays#}
21972240
{#header_close#}
2241+
{#header_close#}
2242+
21982243
{#header_open|struct#}
21992244
{#code_begin|test|structs#}
22002245
// Declare a struct.

0 commit comments

Comments
 (0)