Getting silly with C: four tricks that break GCC's parser

Getting silly with C, part and((int*)-8)[3]

Getting silly with C: four tricks that break GCC's parser

In the fourth installment of his C humor series, lcamtuf demonstrates four code snippets that exploit glitches in GCC's parser, including a K&R-style function declaration with unnamed parameters and an empty union type. The post explains how these tricks work, such as using && as a label address operator and zero-sized types to make pointer arithmetic a no-op.

First, this is sort-of a K&R function declaration, *except* K&R function declarations are no longer accepted by GCC: "int x() int foo; { }" -> "error: old-style parameter declarations".
  1. pkasting

    The common theme of this whole series of articles is basically "GCC extensions allow abominations".

  2. nneonneo

    Some of the previous editions came with explainers, but this one doesn't, so here's what's going on:

    `void main() void;`: Despite sort of looking like an independent declaration (which threw me for a loop initially), this is actually an old-style C function definition in disguise. This style of function definition looks like `int foo(a, b, c) int a; int b; int c; { return a * b + c; }`. Without the misleading spacing, the blog code becomes `void main() void; void; { puts("hello world"); }`, in which it is clear that this is an old-style function definition with two useless declarations attached (void;). This one is both standard and free of UB.

    `int typedef[[]]$;`: This is a combination of a few features: (1) $ is allowed as a legal identifier by some C compilers, (2) [[]] is an empty C23 attribute specifier sequence (basically a standardized form of __attribute__), (3) && is both the familiar binary operator, and (as a GCC extension) a unary operator that takes the address of a label, and (4) `typedef` doesn't have to be the first keyword in a typedef definition. So, `int typedef[[]]$;` is simply `typedef int $;` - defining $ as a type alias for int. `int main($[[]]$)` says that `main` takes one argument - an `int` (typedef'd $) called `$`. `[[]]$:&&$&&$&&puts("hello world");` defines a label called `$`, then breaks down as `&&$ && $ && puts(...)` - take the address of the label `$`, logical AND the argument `$`, logical AND the result of `puts`. This one uses non-standard f […]

More from this day

2026-08-21