@@ -546,7 +546,10 @@ pub fn main() void {
546
546
{#header_close#}
547
547
{#header_open|String Literals and Character Literals#}
548
548
<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#}.
550
553
</p>
551
554
<p>
552
555
Character literals have type {#syntax#}comptime_int{#endsyntax#}, the same as
@@ -558,20 +561,15 @@ const assert = @import("std").debug.assert;
558
561
const mem = @import("std").mem;
559
562
560
563
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 );
566
569
assert('e' == '\x65');
567
570
assert('\u{1f4a9}' == 128169);
568
571
assert('💯' == 128175);
569
572
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);
575
573
}
576
574
{#code_end#}
577
575
{#see_also|Arrays|Zig Test|Source Encoding#}
@@ -641,23 +639,6 @@ const hello_world_in_c =
641
639
\\}
642
640
;
643
641
{#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>
661
642
{#see_also|@embedFile#}
662
643
{#header_close#}
663
644
{#header_close#}
@@ -1638,12 +1619,11 @@ comptime {
1638
1619
assert(message.len == 5);
1639
1620
}
1640
1621
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".* ;
1643
1624
1644
1625
comptime {
1645
1626
assert(mem.eql(u8, message, same_message));
1646
- assert(@typeOf(message) == @typeOf(same_message));
1647
1627
}
1648
1628
1649
1629
test "iterate over an array" {
@@ -1799,6 +1779,26 @@ test "multidimensional arrays" {
1799
1779
}
1800
1780
{#code_end#}
1801
1781
{#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#}
1802
1802
{#header_close#}
1803
1803
1804
1804
{#header_open|Vectors#}
@@ -2111,6 +2111,29 @@ test "allowzero" {
2111
2111
}
2112
2112
{#code_end#}
2113
2113
{#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#}
2114
2137
{#header_close#}
2115
2138
2116
2139
{#header_open|Slices#}
@@ -2194,7 +2217,29 @@ test "slice widening" {
2194
2217
}
2195
2218
{#code_end#}
2196
2219
{#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#}
2197
2240
{#header_close#}
2241
+ {#header_close#}
2242
+
2198
2243
{#header_open|struct#}
2199
2244
{#code_begin|test|structs#}
2200
2245
// Declare a struct.
0 commit comments