fuhsnn
My recent favorite is glibc's hack to implement _Static_assert under C99: https://codebrowser.dev/glibc/glibc/misc/sys/cdefs.h.html#56...

It uses the constant expression to create a bitfield of size -1 when failed, and leaves the compiler to error on that as the intended assertion. The actual statement is an extern pointer to a function returning a pointer to an array which has sizeof the aforementioned bitfield struct as its size.

Another one encountered in Toybox is (0 || "foo") being a const expression that evaluates to 1. Apparently the string literal must have been soundly created in data section, so its pointer address is safely assumed to be non-zero.

wolfspaw
Really liked the trick of defining the struct in the return part of the function.

Array pointers: Array to pointer decay is extremely annoying, if it was implemented as Array to "slice" decay it would be great.

Static array indices in function parameter declarations: awesome, a shame that C++ (and Tiny C) do not support it >/

flexible array member: extremely useful, and now there are good compiler flags for ensuring correct flexible array member usage

X-Macro: nice, no-overhead enum to string name. Didn't know the trick

Combining default, named and positional arguments: Named-arguments/default-arg, C version xD. It would be cool if it was added to C language as a native feature, instead of having to do the struct hiding macro.

Comma operator: really useful, specially in macros

Digraphs, trigraphs and alternative tokens: di/tri/graphs rarely useful, alternatives synonims of iso646.h are awesome, love using and/or instead of &&/||

Designated initializer: super awesome, could not use if you wanted C++ portability. Now C++ supports some part of it.

Compound literals: fantastic, but in C++ it will explode due to stack deallocation in the same line. C++ should fix this and allow the C idiom >/

Bit fields: nice for more control of structs layout

constant string concat: "MultiLine" String, C version xD

Ad hoc struct declaration in the return type of a function: didn't know this trick, "multi value" return, C version xD

Cosmopolitan-libc: incredible project. Already knew of it, its awesome to offer a binary that runs in all S.Os at the same time.

Evaluate sizeof at compile time by causing duplicate case error: ha, nice trick for debugging the size of anything.

lifthrasiir
I hate I know all of them...

> Backslash line splicing

One reason a trigraph was gone is that `??/`, a trigraph spelling for `\`, also acted like `\` in this context.

> Using `&&` and `||` as conditionals

Not only this is uncommon, but chaining them is not always correct because `a && b || c` doesn't equal to `a ? b : c` when `b` evaluates to false.

> Compile time assumption checking using `enum`s

Please use `static_assert` already.

> Matching character classes with `sscanf()`

This can be combined with `*` to ignore certain characters. For example `%*[ \t]` will skip all horizontal whitespaces, unlike a plain whitespace which will also skip newlines.

> Detecting constant expressions

This ultimately comes from C's weird way to say a null pointer, which is defined as any constant expression which type is inferred to be pointer. So a non-constant expression can be distinguished by multiplying it with a known zero constant.

saagarjha
Mentioning %n without explaining that it is overwhelmingly used for exploits is a little reckless IMO.
coreyp_1
That's a nice list!

I've been digging into cross-platform (Windows and Linux) C for a while, and it has been fascinating. On top of that, I've been writing a JIT-ted scripting (templating) language, and the ABI differences (not just fastcall vs stdcall vs cdecl) are often not easy to find documentation about.

I've decided that if I ever get to teach a University class on C again, I wanted to cover some of these things that I feel are often left out, and this list is a helpful reference! Thanks!

winocm
There’s also the use of typedef to help make function declarations.

Such as:

  typedef void fptr_t(int);
  fptr_t foo;
That would effectively declare a function with the prototype: `void foo(int)'. This pattern is used quite a bit in BSD kernels.
jonathrg
Multi character constants is one of the many things in C that would be nice to use if the language would just choose some well-defined behaviour for it. It doesn't really matter which.
johnklos
Not sure what happened:

404

File not found

The site configured at this address does not contain the requested file.

golergka

    switch (n % 2) {
        case 0:
            do {
                ++i;
        case 1:
                ++i;
            } while (--n > 0);

    }
Someone is really ought to record a "WAT" video about C.
38

    > int (*ap1)[10] = &arr;
Wow that's garbage syntax. With Go it would be

    var ap1 *[10]int = &arr
guerrilla
These are great. Most posts I read with titles similar to this are just the authors revealing that they don't know C very well but this one included some interesting things. I didn't know compund literals were lvalues but if you think about executable formats, it makes a lot of sense.
ranger_danger
> quirks and features

Someone is a fan of Doug DeMuro.

o11c
Bah, those are all well-known.

What value does the following program return?

    int main()
    {
        int *p = 0;

    loop:
        if (p)
            return *p;

        int v = 1;
        p = &v;
        v = 2;
        goto loop;
        return 3;
    }
Also, rather than doing `sizeof` via one error at a time, it's better to just emit them to a char array {'0' + sz/10, '0' + sz%10, '\0'}. Generalizing this to signed numbers of arbitrary size is left as an exercise for the reader.