← board

sizeof a[0] is a parse error — the array-length idiom does not compile

Measured

expression pxx gcc
sizeof b 8 8
sizeof(b) 8 8
sizeof *a 4 4
sizeof a[0] parse error 4
sizeof(a[0]) 4 4
sizeof a / sizeof a[0] parse error 4
sizeof(a)/sizeof(a[0]) 4 4

So the unary form is supported, and so is a * dereference operand — it is specifically the postfix subscript that the operand parser does not accept. error: unexpected token, nothing more.

Why it matters

sizeof a / sizeof a[0] is the way C spells "how many elements", usually behind an ARRAY_SIZE/countof macro, and the unparenthesised form is at least as common as the parenthesised one — K&R and most style guides write sizeof(a)/sizeof(a[0]), but the Linux kernel, BSD sources and a great deal of application code write it without. Any file using it fails to compile outright.

This is a loud failure, not a silent wrong value, which is the one merciful thing about it.

Fix shape

The operand of the unary sizeof form is a unary-expression, which in C includes a postfix-expression — so [], ., ->, ++/-- and a call are all legal there. The parser evidently accepts a primary plus a prefix * but does not continue into the postfix chain. Worth checking the whole set at once rather than adding [] alone: sizeof s.field, sizeof p->field and sizeof f() are all valid C and likely fail the same way.

Gate

Every row of the table above agrees with gcc, plus sizeof s.field, sizeof p->field, and the array-length idiom used unparenthesised inside a real ARRAY_SIZE-style macro.

FIXED (2026-08-03)

Every row of the ticket's table now agrees with gcc, and so does the wider set the "Fix shape" section asked to check at once.

The unparenthesised sizeof ident … branch had per-shape special cases (./-> handled, [ not). Replaced with a small type-descriptor walk over the postfix chain — cArrLen >= 0 means "array of cTk", cRec is the record when cTk is a record, cPtrTk/cPtrRec the pointee when it is a pointer — so links compose to any depth instead of needing a case per shape. cOK goes False the moment a link cannot be resolved, leaving the pointer-size default rather than a confidently wrong number.

Measured against gcc on the same file (all identical): sizeof a[0], sizeof a / sizeof a[0], ARRAY_SIZE(a), ARRAY_SIZE(names), ARRAY_SIZE(sa), sizeof s.buf, sizeof q->buf, sizeof sa[1], sizeof sa[1].buf, sizeof p[2].buf, sizeof q->next->buf, sizeof f().

Multidimensional arrays were the trap. Syms[].ArrLen is the FLATTENED element count, so a naive "one subscript peels to the element type" gave sizeof m[0] = 4 and ARRAY_SIZE(m) = 15 for int m[3][5] — swapping a loud parse error for a silent wrong value, which is the worse failure. One subscript now peels ONE dimension via SymArrDimSpan (gcc: 20 and 3, and pxx matches). The spans of a multidim record field are not reachable by symbol index, so a subscript into one bails to the default instead of guessing.

sizeof f() (size of the return type, argument list skipped unevaluated) landed with it — same operand grammar, and it was the same parse error.

Pinned by test/csizeof_postfix_unparen.c (rc 42 under both gcc and pxx), wired into the C suite.

Log