Name
n3989, alx-0081r5 - array parameters of 0 elements
Principles
- Uphold the character of the language
- Codify existing practice to address evident deficiencies
- Enable secure programming
And from previous charters:
C23:
- APIs should be self-documenting when possible.
Category
Language; array parameters.
Author
Alejandro Colomar <alx@kernel.org>
Acked-by: Martin Uecker <uecker@tugraz.at>
Acked-by: Doug McIlroy
Acked-by: Andrew Clayton <ac@sigsegv.uk>
Acked-by: Alex Celeste <alexg.nvfp@gmail.com>
History
<https://www.alejandro-colomar.es/src/alx/alx/std/wg14/alx-0081.git/>
r0 (2026-01-25):
- Initial draft.
r1 (2026-01-25):
- Array length expressions shall be nonnegative.
r2 (2026-01-26):
- Acked-by.
- Remove 'See also'.
r3 (2026-02-01; n3802):
- Acked-by.
Ottawa meeting (2026-08-19):
- Seacord: We should add it in to support Rust.
- Bhakta: I like the general idea.
- Celeste: I support this, ...
- Ballman: This is reasonable, ...
r4 (2026-08-22):
- Add 'Prior art'.
- Acked-by: Martin.
r5 (2026-10-11, n3989):
- Mention Plan9 needs this behavior.
- Mention static analysis.
- No compilers found that misbehave for this.
- Document Ottawa meeting.
- Rebase.
Abstract
Function parameters that have zero elements are common and safe.
Let's acknowledge this, and allow array syntax for them.
This will improve static analysis.
Discussion
The following code is valid:
static inline wchar_t
my_wmemset(size_t n, wchar_t *wcs, wchar_t wc)
{
return wmemset(wcs, wc, n);
}
wchar_t a[42];
my_wmemset(0, a + 42, L'x');
It would be natural to be able to declare my_wmemset() as
wchar_t my_wmemset(size_t n, wchar_t wcs[static n], wchar_t);
However, that would result in UB for the call above, as the
number of elements isn't allowed to be zero. That restriction
is superfluous, and harmful; let's remove it.
Prior art
All compilers I've tried fall into two categories:
- Some compilers reject [0]. I've only seen cc65 do this.
- Most compilers accept this code as an extension, and produce
the expected code.
Notably, I didn't find any compilers that misbehave for this
code. I've asked in case anyone knows of any, but nobody could
find any.
Also, while some compilers reject [0], all compilers seem to
accept passing 0 to a parameter used as the length of an array
parameter, and produce the expected code.
Compilers must support this, because many programs already rely
on this behavior, so misbehaving would break a lot of existing
programs.
Plan9 has libc functions that rely on this behavior being
supported: seprint(2) and strecpy(2).
Flex arrays
Some mentioned that this might be confused with old flex arrays
in GNU C. However, GCC is precisely the compiler with best
support for array parameters of zero elements.
Also, while [0] might be an interesting special case for
a sentinel pointer, the case of [n] where n==0 is more
important, and it is the most spread case of array parameters of
zero elements. We must support it.
Future directions
I'd like to allow any arrays of zero elements, but that needs
to be more careful than for array parameters. A future proposal
will address that.
Comments
On 2026-01-25T18:19:02-0500, Douglas McIlroy wrote:
> All six proposals look eminently reasonable. They simplify
> the language and remove surprises. I suspect these proposals
> will invalidate very few existing programs. In any event, the
> required corrections will improve the legibility and
> maintainability of such programs.
>
> Doug McIlroy
---
On 2026-01-26T02:01:16+0000, Alex Celeste wrote:
> Like Martin - these all seem eminently reasonable to me.
Proposed wording
Based on N3886.
6.7.7.3 Array declarators
@@ Constraints, p1
In addition to optional type qualifiers and the keyword static,
the [ and ] can delimit an expression or *.
If they delimit an expression,
called the array length expression,
the expression shall have an integer type.
If the expression is a constant expression,
-it shall have a value greater than zero.
+it shall have a nonnegative value.
+An array length expression
+that is a constant expression with value zero
+shall appear only in
+a declaration of a function parameter with an array type,
+and then only in the outermost array type derivation.
The element type shall not be an incomplete or function type.
The optional type qualifiers and the keyword static
shall appear only in
a declaration of a function parameter with an array type,
and then only in the outermost array type derivation.
@@ Semantics, p5
If the array length expression
is not an integer constant expression:
if it occurs in a declaration
at function prototype scope
or in a type name of a generic association (as described above),
it is treated as if it were replaced by *;
otherwise,
each time it is evaluated,
-it shall have a value greater than zero.
+it shall have a value greater than zero,
+unless in the outermost array type derivation
+of a function parameter with an array type,
+in which case it shall have a nonnegative value.
The size of each instance of a variable length array type
does not change during its lifetime.
Where an array length expression
is part of the operand of the typeof or sizeof operators
and changing the value of the array length expression
would not affect the result of the operator,
it is unspecified
whether or not the array length expression is evaluated.
Where an array length expression is part of
the operand with a _Countof operator
and changing the value of the array length expression
would not affect the result of the operator,
the array length expression is not evaluated.
Where an array length expression is part of
the operand of an alignof operator,
that expression is not evaluated.