- Undefined Behavior
- Reaching Unreachable Code
- Index out of Bounds
- Cast Negative Number to Unsigned Integer
- Cast Truncates Data
- Integer Overflow
- Exact Left Shift Overflow
- Exact Right Shift Overflow
- Division by Zero
- Remainder Division by Zero
- Exact Division Remainder
- Attempt to Unwrap Null
- Attempt to Unwrap Error
- Invalid Error Code
- Invalid Enum Cast
- Invalid Error Set Cast
- Incorrect Pointer Alignment
- Wrong Union Field Access
- Out of Bounds Float to Integer Cast
- Pointer Cast Invalid Null
Undefined Behavior
Zig has many instances of undefined behavior. If undefined behavior is detected at compile-time, Zig emits a compile error and refuses to continue. Most undefined behavior that cannot be detected at compile-time can be detected at runtime. In these cases, Zig has safety checks. Safety checks can be disabled on a per-block basis with @setRuntimeSafety. The ReleaseFast and ReleaseSmall build modes disable all safety checks (except where overridden by @setRuntimeSafety) in order to facilitate optimizations.
When a safety check fails, Zig crashes with a stack trace, like this:
test.zig
test "safety check"{
unreachable;
}
$ zig test test.zig
1/1 test "safety check"...reached unreachable code
/deps/zig/docgen_tmp/test.zig:2:5:0x204b9ain test "safety check"(test)
unreachable;
^
/deps/zig/lib/std/special/test_runner.zig:47:28:0x22ba9ein std.special.main (test)
}else test_fn.func();
^
/deps/zig/lib/std/start.zig:253:37:0x2055cdin std.start.posixCallMainAndExit (test)
const result = root.main()catch|err|{
^
/deps/zig/lib/std/start.zig:123:5:0x20530fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
Tests failed.Use the following command to reproduce the failure:
/deps/zig/docgen_tmp/test
Reaching Unreachable Code
At compile-time:
test.zig
comptime {
assert(false);
}
fn assert(ok:bool)void{
if(!ok) unreachable;// assertion failure
}
$ zig test test.zig
./docgen_tmp/test.zig:5:14: error: unable to evaluate constant expression
if(!ok) unreachable;// assertion failure
^
./docgen_tmp/test.zig:2:11: note: called from here
assert(false);
^
./docgen_tmp/test.zig:1:10: note: called from here
comptime {
^
./docgen_tmp/test.zig:2:11: note: referenced here
assert(false);
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
std.debug.assert(false);
}
$ zig build-exe test.zig
$ ./test
reached unreachable code
/deps/zig/lib/std/debug.zig:228:14:0x203cbbin std.debug.assert(test)
if(!ok) unreachable;// assertion failure
^
/deps/zig/docgen_tmp/test.zig:4:21:0x22a7dain main (test)
std.debug.assert(false);
^
/deps/zig/lib/std/start.zig:243:22:0x2046dfin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x2044bfin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Index out of Bounds
At compile-time:
test.zig
comptime {
const array:[5]u8 ="hello".*;
const garbage = array[5];
}
$ zig test test.zig
./docgen_tmp/test.zig:3:26: error: index 5 outside array of size 5
const garbage = array[5];
^
At runtime:
test.zig
pub fn main()void{
var x = foo("hello");
}
fn foo(x:[]const u8) u8 {
return x[5];
}
$ zig build-exe test.zig
$ ./test
index out of bounds
/deps/zig/docgen_tmp/test.zig:6:13:0x22e969in foo (test)
return x[5];
^
/deps/zig/docgen_tmp/test.zig:2:16:0x22a7e6in main (test)
var x = foo("hello");
^
/deps/zig/lib/std/start.zig:243:22:0x2046dfin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x2044bfin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Cast Negative Number to Unsigned Integer
At compile-time:
test.zig
comptime {
const value: i32 =-1;
constunsigned=@intCast(u32, value);
}
$ zig test test.zig
./docgen_tmp/test.zig:3:36: error: cannot cast negative value -1 to unsigned integer type 'u32'
constunsigned=@intCast(u32, value);
^
./docgen_tmp/test.zig:3:22: note: referenced here
constunsigned=@intCast(u32, value);
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
var value: i32 =-1;
varunsigned=@intCast(u32, value);
std.debug.warn("value: {}\n",.{unsigned});
}
$ zig build-exe test.zig
$ ./test
attempt to cast negative value to unsigned integer
/deps/zig/docgen_tmp/test.zig:5:20:0x22a867in main (test)
varunsigned=@intCast(u32, value);
^
/deps/zig/lib/std/start.zig:243:22:0x20472fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20450fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
To obtain the maximum value of an unsigned integer, use std.math.maxInt
.
Cast Truncates Data
At compile-time:
test.zig
comptime {
const spartan_count: u16 =300;
constbyte=@intCast(u8, spartan_count);
}
$ zig test test.zig
./docgen_tmp/test.zig:3:31: error: integer value 300 cannot be coerced to type 'u8'
constbyte=@intCast(u8, spartan_count);
^
./docgen_tmp/test.zig:3:18: note: referenced here
constbyte=@intCast(u8, spartan_count);
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
var spartan_count: u16 =300;
constbyte=@intCast(u8, spartan_count);
std.debug.warn("value: {}\n",.{byte});
}
$ zig build-exe test.zig
$ ./test
integer cast truncated bits
/deps/zig/docgen_tmp/test.zig:5:18:0x22a86cin main (test)
constbyte=@intCast(u8, spartan_count);
^
/deps/zig/lib/std/start.zig:243:22:0x20472fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20450fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
To truncate bits, use @truncate.
Integer Overflow
Default Operations
The following operators can cause integer overflow:
+
(addition)-
(subtraction)-
(negation)*
(multiplication)/
(division)- @divTrunc (division)
- @divFloor (division)
- @divExact (division)
Example with addition at compile-time:
test.zig
comptime {
varbyte: u8 =255;
byte+=1;
}
$ zig test test.zig
./docgen_tmp/test.zig:3:10: error: operation caused overflow
byte+=1;
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
varbyte: u8 =255;
byte+=1;
std.debug.warn("value: {}\n",.{byte});
}
$ zig build-exe test.zig
$ ./test
integer overflow
/deps/zig/docgen_tmp/test.zig:5:10:0x22a850in main (test)
byte+=1;
^
/deps/zig/lib/std/start.zig:243:22:0x20472fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20450fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Standard Library Math Functions
These functions provided by the standard library return possible errors.
@import("std").math.add
@import("std").math.sub
@import("std").math.mul
@import("std").math.divTrunc
@import("std").math.divFloor
@import("std").math.divExact
@import("std").math.shl
Example of catching an overflow for addition:
test.zig
const math =@import("std").math;
const warn =@import("std").debug.warn;
pub fn main()!void{
varbyte: u8 =255;
byte=if(math.add(u8,byte,1))|result| result else|err|{
warn("unable to add one: {}\n",.{@errorName(err)});
return err;
};
warn("result: {}\n",.{byte});
}
$ zig build-exe test.zig
$ ./test
unable to add one:Overflow
error:Overflow
/deps/zig/lib/std/math.zig:342:5:0x22ee70in std.math.add (test)
returnif(@addWithOverflow(T, a, b,&answer)) error.Overflowelse answer;
^
/deps/zig/docgen_tmp/test.zig:8:9:0x22ab3bin main (test)
return err;
^
Builtin Overflow Functions
These builtins return a bool
of whether or not overflow occurred, as well as returning the overflowed bits:
Example of @addWithOverflow:
test.zig
const warn =@import("std").debug.warn;
pub fn main()void{
varbyte: u8 =255;
var result: u8 =undefined;
if(@addWithOverflow(u8,byte,10,&result)){
warn("overflowed result: {}\n",.{result});
}else{
warn("result: {}\n",.{result});
}
}
$ zig build-exe test.zig
$ ./test
overflowed result:9
Wrapping Operations
These operations have guaranteed wraparound semantics.
+%
(wraparound addition)-%
(wraparound subtraction)-%
(wraparound negation)*%
(wraparound multiplication)
test.zig
const std =@import("std");
constassert= std.debug.assert;
const minInt = std.math.minInt;
const maxInt = std.math.maxInt;
test "wraparound addition and subtraction"{
const x: i32 = maxInt(i32);
const min_val = x +%1;
assert(min_val == minInt(i32));
const max_val = min_val -%1;
assert(max_val == maxInt(i32));
}
$ zig test test.zig
1/1 test "wraparound addition and subtraction"...OK
All1 tests passed.
Exact Left Shift Overflow
At compile-time:
test.zig
comptime {
const x =@shlExact(@as(u8,0b01010101),2);
}
$ zig test test.zig
./docgen_tmp/test.zig:2:15: error: operation caused overflow
const x =@shlExact(@as(u8,0b01010101),2);
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
var x: u8 =0b01010101;
var y =@shlExact(x,2);
std.debug.warn("value: {}\n",.{y});
}
$ zig build-exe test.zig
$ ./test
left shift overflowed bits
/deps/zig/docgen_tmp/test.zig:5:13:0x22a89din main (test)
var y =@shlExact(x,2);
^
/deps/zig/lib/std/start.zig:243:22:0x20475fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20453fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Exact Right Shift Overflow
At compile-time:
test.zig
comptime {
const x =@shrExact(@as(u8,0b10101010),2);
}
$ zig test test.zig
./docgen_tmp/test.zig:2:15: error: exact shift shifted out1 bits
const x =@shrExact(@as(u8,0b10101010),2);
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
var x: u8 =0b10101010;
var y =@shrExact(x,2);
std.debug.warn("value: {}\n",.{y});
}
$ zig build-exe test.zig
$ ./test
right shift overflowed bits
/deps/zig/docgen_tmp/test.zig:5:13:0x22a89din main (test)
var y =@shrExact(x,2);
^
/deps/zig/lib/std/start.zig:243:22:0x20475fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20453fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Division by Zero
At compile-time:
test.zig
comptime {
const a: i32 =1;
const b: i32 =0;
const c = a / b;
}
$ zig test test.zig
./docgen_tmp/test.zig:4:17: error: division by zero
const c = a / b;
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
var a: u32 =1;
var b: u32 =0;
var c = a / b;
std.debug.warn("value: {}\n",.{c});
}
$ zig build-exe test.zig
$ ./test
division by zero
/deps/zig/docgen_tmp/test.zig:6:15:0x22a859in main (test)
var c = a / b;
^
/deps/zig/lib/std/start.zig:243:22:0x20472fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20450fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Remainder Division by Zero
At compile-time:
test.zig
comptime {
const a: i32 =10;
const b: i32 =0;
const c = a % b;
}
$ zig test test.zig
./docgen_tmp/test.zig:4:17: error: division by zero
const c = a % b;
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
var a: u32 =10;
var b: u32 =0;
var c = a % b;
std.debug.warn("value: {}\n",.{c});
}
$ zig build-exe test.zig
$ ./test
remainder division by zero or negative value
/deps/zig/docgen_tmp/test.zig:6:15:0x22a87bin main (test)
var c = a % b;
^
/deps/zig/lib/std/start.zig:243:22:0x20472fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20450fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Exact Division Remainder
At compile-time:
test.zig
comptime {
const a: u32 =10;
const b: u32 =3;
const c =@divExact(a, b);
}
$ zig test test.zig
./docgen_tmp/test.zig:4:15: error: exact division had a remainder
const c =@divExact(a, b);
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
var a: u32 =10;
var b: u32 =3;
var c =@divExact(a, b);
std.debug.warn("value: {}\n",.{c});
}
$ zig build-exe test.zig
$ ./test
exact division produced remainder
/deps/zig/docgen_tmp/test.zig:6:13:0x22a89din main (test)
var c =@divExact(a, b);
^
/deps/zig/lib/std/start.zig:243:22:0x20472fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20450fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Attempt to Unwrap Null
At compile-time:
test.zig
comptime {
const optional_number:?i32 =null;
const number = optional_number.?;
}
$ zig test test.zig
./docgen_tmp/test.zig:3:35: error: unable to unwrap null
const number = optional_number.?;
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
var optional_number:?i32 =null;
var number = optional_number.?;
std.debug.warn("value: {}\n",.{number});
}
$ zig build-exe test.zig
$ ./test
attempt to usenull value
/deps/zig/docgen_tmp/test.zig:5:33:0x22a86cin main (test)
var number = optional_number.?;
^
/deps/zig/lib/std/start.zig:243:22:0x20474fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20452fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
One way to avoid this crash is to test for null instead of assuming non-null, with the if
expression:
test.zig
const warn =@import("std").debug.warn;
pub fn main()void{
const optional_number:?i32 =null;
if(optional_number)|number|{
warn("got number: {}\n",.{number});
}else{
warn("it's null\n",.{});
}
}
$ zig build-exe test.zig
$ ./test
it's null
See also:
Attempt to Unwrap Error
At compile-time:
test.zig
comptime {
const number = getNumberOrFail()catch unreachable;
}
fn getNumberOrFail()!i32 {
return error.UnableToReturnNumber;
}
$ zig test test.zig
./docgen_tmp/test.zig:2:38: error: caught unexpected error 'UnableToReturnNumber'
const number = getNumberOrFail()catch unreachable;
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
const number = getNumberOrFail()catch unreachable;
std.debug.warn("value: {}\n",.{number});
}
fn getNumberOrFail()!i32 {
return error.UnableToReturnNumber;
}
$ zig build-exe test.zig
$ ./test
attempt to unwrap error:UnableToReturnNumber
/deps/zig/docgen_tmp/test.zig:9:5:0x22ea6cin getNumberOrFail (test)
return error.UnableToReturnNumber;
^
???:?:?:0x20698cin???(???)
/deps/zig/docgen_tmp/test.zig:4:38:0x22a8cbin main (test)
const number = getNumberOrFail()catch unreachable;
^
/deps/zig/lib/std/start.zig:243:22:0x20476fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20454fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
One way to avoid this crash is to test for an error instead of assuming a successful result, with the if
expression:
test.zig
const warn =@import("std").debug.warn;
pub fn main()void{
const result = getNumberOrFail();
if(result)|number|{
warn("got number: {}\n",.{number});
}else|err|{
warn("got error: {}\n",.{@errorName(err)});
}
}
fn getNumberOrFail()!i32 {
return error.UnableToReturnNumber;
}
$ zig build-exe test.zig
$ ./test
got error:UnableToReturnNumber
See also:
Invalid Error Code
At compile-time:
test.zig
comptime {
const err = error.AnError;
const number =@errorToInt(err)+10;
const invalid_err =@intToError(number);
}
$ zig test test.zig
./docgen_tmp/test.zig:4:25: error: integer value 11 represents no error
const invalid_err =@intToError(number);
^
At runtime:
test.zig
const std =@import("std");
pub fn main()void{
var err = error.AnError;
var number =@errorToInt(err)+500;
var invalid_err =@intToError(number);
std.debug.warn("value: {}\n",.{number});
}
$ zig build-exe test.zig
$ ./test
invalid error code
/deps/zig/docgen_tmp/test.zig:6:23:0x22a8b4in main (test)
var invalid_err =@intToError(number);
^
/deps/zig/lib/std/start.zig:243:22:0x20475fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20453fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Invalid Enum Cast
At compile-time:
test.zig
constFoo=enum{
A,
B,
C,
};
comptime {
const a: u2 =3;
const b =@intToEnum(Foo, a);
}
$ zig test test.zig
./docgen_tmp/test.zig:8:15: error:enum'Foo' has no tag matching integer value 3
const b =@intToEnum(Foo, a);
^
./docgen_tmp/test.zig:1:13: note:'Foo' declared here
constFoo=enum{
^
At runtime:
test.zig
const std =@import("std");
constFoo=enum{
A,
B,
C,
};
pub fn main()void{
var a: u2 =3;
var b =@intToEnum(Foo, a);
std.debug.warn("value: {}\n",.{@tagName(b)});
}
$ zig build-exe test.zig
$ ./test
invalid enum value
/deps/zig/docgen_tmp/test.zig:11:13:0x22a8ccin main (test)
var b =@intToEnum(Foo, a);
^
/deps/zig/lib/std/start.zig:243:22:0x20479fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20457fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Invalid Error Set Cast
At compile-time:
test.zig
constSet1= error{
A,
B,
};
constSet2= error{
A,
C,
};
comptime {
_ =@errSetCast(Set2,Set1.B);
}
$ zig test test.zig
./docgen_tmp/test.zig:10:9: error: error.B not a member of error set'Set2'
_ =@errSetCast(Set2,Set1.B);
^
At runtime:
test.zig
const std =@import("std");
constSet1= error{
A,
B,
};
constSet2= error{
A,
C,
};
pub fn main()void{
foo(Set1.B);
}
fn foo(set1:Set1)void{
const x =@errSetCast(Set2, set1);
std.debug.warn("value: {}\n",.{x});
}
$ zig build-exe test.zig
$ ./test
invalid error code
/deps/zig/docgen_tmp/test.zig:15:15:0x22ea4cin foo (test)
const x =@errSetCast(Set2, set1);
^
/deps/zig/docgen_tmp/test.zig:12:8:0x22a89din main (test)
foo(Set1.B);
^
/deps/zig/lib/std/start.zig:243:22:0x20479fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x20457fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Incorrect Pointer Alignment
At compile-time:
test.zig
comptime {
const ptr =@intToPtr(*align(1) i32,0x1);
const aligned =@alignCast(4, ptr);
}
$ zig test test.zig
./docgen_tmp/test.zig:3:35: error: pointer address 0x1isnot aligned to 4 bytes
const aligned =@alignCast(4, ptr);
^
./docgen_tmp/test.zig:3:21: note: referenced here
const aligned =@alignCast(4, ptr);
^
At runtime:
test.zig
const mem =@import("std").mem;
pub fn main()!void{
var array align(4)=[_]u32{0x11111111,0x11111111};
const bytes = mem.sliceAsBytes(array[0..]);
if(foo(bytes)!=0x11111111)return error.Wrong;
}
fn foo(bytes:[]u8) u32 {
const slice4 = bytes[1..5];
const int_slice = mem.bytesAsSlice(u32,@alignCast(4, slice4));
return int_slice[0];
}
$ zig build-exe test.zig
$ ./test
incorrect alignment
/deps/zig/docgen_tmp/test.zig:9:59:0x22edbbin foo (test)
const int_slice = mem.bytesAsSlice(u32,@alignCast(4, slice4));
^
/deps/zig/docgen_tmp/test.zig:5:12:0x22aa49in main (test)
if(foo(bytes)!=0x11111111)return error.Wrong;
^
/deps/zig/lib/std/start.zig:253:37:0x2047edin std.start.posixCallMainAndExit (test)
const result = root.main()catch|err|{
^
/deps/zig/lib/std/start.zig:123:5:0x20452fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
Wrong Union Field Access
At compile-time:
test.zig
comptime {
var f =Foo{.int=42};
f.float=12.34;
}
constFoo=union{
float: f32,
int: u32,
};
$ zig test test.zig
./docgen_tmp/test.zig:3:6: error: accessing union field 'float'while field 'int'isset
f.float=12.34;
^
At runtime:
test.zig
const std =@import("std");
constFoo=union{
float: f32,
int: u32,
};
pub fn main()void{
var f =Foo{.int=42};
bar(&f);
}
fn bar(f:*Foo)void{
f.float=12.34;
std.debug.warn("value: {}\n",.{f.float});
}
$ zig build-exe test.zig
$ ./test
access of inactive union field
/deps/zig/docgen_tmp/test.zig:14:6:0x23c21ain bar (test)
f.float=12.34;
^
/deps/zig/docgen_tmp/test.zig:10:8:0x23806cin main (test)
bar(&f);
^
/deps/zig/lib/std/start.zig:243:22:0x211f5fin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x211d3fin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)
This safety is not available for extern
or packed
unions.
To change the active field of a union, assign the entire union, like this:
test.zig
const std =@import("std");
constFoo=union{
float: f32,
int: u32,
};
pub fn main()void{
var f =Foo{.int=42};
bar(&f);
}
fn bar(f:*Foo)void{
f.*=Foo{.float=12.34};
std.debug.warn("value: {}\n",.{f.float});
}
$ zig build-exe test.zig
$ ./test
value:1.23400001e+01
To change the active field of a union when a meaningful value for the field is not known, use undefined, like this:
test.zig
const std =@import("std");
constFoo=union{
float: f32,
int: u32,
};
pub fn main()void{
var f =Foo{.int=42};
f =Foo{.float=undefined};
bar(&f);
std.debug.warn("value: {}\n",.{f.float});
}
fn bar(f:*Foo)void{
f.float=12.34;
}
$ zig build-exe test.zig
$ ./test
value:1.23400001e+01
See also:
Out of Bounds Float to Integer Cast
TODO
Pointer Cast Invalid Null
This happens when casting a pointer with the address 0 to a pointer which may not have the address 0. For example, C Pointers, Optional Pointers, and allowzero pointers allow address zero, but normal Pointers do not.
At compile-time:
test.zig
comptime {
const opt_ptr:?*i32 =null;
const ptr =@ptrCast(*i32, opt_ptr);
}
$ zig test test.zig
./docgen_tmp/test.zig:3:17: error:null pointer casted to type '*i32'
const ptr =@ptrCast(*i32, opt_ptr);
^
At runtime:
test.zig
pub fn main()void{
var opt_ptr:?*i32 =null;
var ptr =@ptrCast(*i32, opt_ptr);
}
$ zig build-exe test.zig
$ ./test
cast causes pointer to be null
/deps/zig/docgen_tmp/test.zig:3:15:0x22a800in main (test)
var ptr =@ptrCast(*i32, opt_ptr);
^
/deps/zig/lib/std/start.zig:243:22:0x2046dfin std.start.posixCallMainAndExit (test)
root.main();
^
/deps/zig/lib/std/start.zig:123:5:0x2044bfin std.start._start (test)
@call(.{.modifier =.never_inline }, posixCallMainAndExit,.{});
^
(process terminated by signal)