C Pointers
const std = @import("std");
const expect = std.testing.expect;
test "a C pointer is the permissive one" {
var value: i32 = 42;
// [*c]T can be null, can be indexed, and coerces freely. It gives up
// every guarantee Zig's other pointer types provide.
const c_ptr: [*c]i32 = &value;
try expect(c_ptr.* == 42);
try expect(c_ptr[0] == 42);
}
test "it coerces to and from the safe types" {
var array = [_]i32{ 1, 2, 3 };
const many: [*]i32 = &array;
const c_ptr: [*c]i32 = many;
const back: [*]i32 = c_ptr;
try expect(back[2] == 3);
}
test "null is representable" {
const c_ptr: [*c]i32 = null;
try expect(c_ptr == null);
}
test "convert at the boundary and use real types inside" {
var array = [_]i32{ 10, 20, 30 };
const c_ptr: [*c]i32 = &array;
// The length is not carried by the pointer; supply it once, then work
// with a bounds-checked slice.
const slice: []i32 = c_ptr[0..3];
try expect(slice.len == 3);
try expect(slice[1] == 20);
}[*c]T is Zig’s model of C’s T*. It exists almost entirely so that
@cImport can translate headers automatically.
It gives up everything
| Property | *T | []T | [*c]T |
|---|---|---|---|
| can be null | no | no | yes |
| carries a length | n/a | yes | no |
| bounds checked | n/a | yes | no |
| indexable | no | yes | yes |
| coerces freely | no | no | yes |
That last row is the dangerous one. A [*c]T converts to and from the safe
pointer types without complaint, which is convenient at a C boundary and
corrosive anywhere else: it silently launders away the guarantees the rest of
the language is built on.
Convert at the boundary
The moment you know the length, produce a slice and never look back:
const slice: []i32 = c_ptr[0..count];
Now you have bounds checks, for iteration, and .len. If the pointer might
be null, check once and turn it into an optional rather than propagating the
uncertainty.
Rule of thumb
If you did not get it from @cImport or an extern declaration, you should
not be writing [*c]. Use *T for one item, [*]T for many, []T when you
know the count, and ? when it may be absent.