Live data from Hacker News

Lesser known tricks, quirks and features of C

blog.joren.ga

31–40 of 189 posts

Re: Lesser known tricks, quirks and features of C

#31

Here's another one. Handy "syntax" that makes it possible to iterate an unsigned type from N-1 to 0. (Normally this is tricky.) for (unsigned int i = N; i --> 0;) printf("%d\n", i); This --> construction also works in JavaScript and so on.

If you're gonna test the i--, shouldn't it fall through on zero anyway?

    for (unsigned int i = N; i--;){}

    unsigned int i = N;
    while(i--){ ... }

Also I think I'm missing the tricky part. Couldn't this be a bog-standard for loop?

   for (unsigned int i = N - 1; i > 0; i--){ ... }
The "downto" pseudooperator definitely scores some points for coolness and aesthetics, but there's no immediately obvious use case for me.

Re: Lesser known tricks, quirks and features of C

#32

Never quite understood why compound literals are lvalues, but fine, whatever, I guess, it's so that you can write "&(struct Foo){};" instead of "struct Foo tmp; &tmp;"... which, on a tangential note, reminds me about Go: the proposals to make things like &5 and &true legal in Go were rejected because "the implied semantics would be unclear" even though &structFoo{} is legal and apparently has obvious semantics.

In C compound literals have a relatively long lifetime compared to C++ temporaries. With these lifetime rules it makes sense that they are lvalues, although I like C++ rvalues (especially prvalues) more.

https://cigix.me/c17#6.5.2.5.p5

> If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

Re: Lesser known tricks, quirks and features of C

#33

Here's another one. Handy "syntax" that makes it possible to iterate an unsigned type from N-1 to 0. (Normally this is tricky.) for (unsigned int i = N; i --> 0;) printf("%d\n", i); This --> construction also works in JavaScript and so on.

If you're gonna test the i--, shouldn't it fall through on zero anyway? for (unsigned int i = N; i--;){} unsigned int i = N; while(i--){ ... } Also I think I'm missing the tricky part. Couldn't this be a bog-standard for loop? for (unsigned int i = N - 1; i > 0; i--){ ... } The "downto" pseudooperator definitely scores some points for coolness and aesthetics, but there's no immediately obvious use case for me.

The former executes loop when `i` is 0.

And we cannot change the comparison to `>=` in the later, because unsigned is always bigger or equal 0, thus we would get infinite loop.

Re: Lesser known tricks, quirks and features of C

#34

Here's another one. Handy "syntax" that makes it possible to iterate an unsigned type from N-1 to 0. (Normally this is tricky.) for (unsigned int i = N; i --> 0;) printf("%d\n", i); This --> construction also works in JavaScript and so on.

how would you iterate over every possible value of a unsigned int?

Re: Lesser known tricks, quirks and features of C

#35
post #6

Fun fact about %n: Mazda cars used to have a bug where they used printf(str) instead of printf("%s", str) and their media system would crash if you tried to play the "99% Invisible" podcast in them. All because the "% In" was parsed as a "%n" with some extra modifiers. https://99percentinvisible.org/episode/the-roman-mars-mazda-...

"format not a string literal" is one warning I always upgrade to an error. Dear reader: you should do this, too!

Re: Lesser known tricks, quirks and features of C

#36
post #35
post #6

Fun fact about %n: Mazda cars used to have a bug where they used printf(str) instead of printf("%s", str) and their media system would crash if you tried to play the "99% Invisible" podcast in them. All because the "% In" was parsed as a "%n" with some extra modifiers. https://99percentinvisible.org/episode/the-roman-mars-mazda-...

"format not a string literal" is one warning I always upgrade to an error. Dear reader: you should do this, too!

Thanks! This prompted me to look up the flag to enable this. For GCC it’s:

  -Werror=format-security

Re: Lesser known tricks, quirks and features of C

#37
post #4

Nice article. Saw a few things I wish I'd known about. 1. %n in printf would be handy when writing CLIs dealing w/ multiple lines or precise counts of backspaces. 2. Using enums as a form of static_assert() is a great idea (triggering a div by zero compiler error).

The enum idea is interesting. I've previously used an extern with a conditional size of either 1 (valid) or -1 (invalid). This requires no additional boilerplate, and is #define-able into a static assert when built with a recent enough compiler. Something like this, from memory:

    #define STATIC_ASSERT(COND) extern char static_assert_cond_[(COND)?1:-1] /* C99 or earlier */
    #define STATIC_ASSERT(COND) _Static_assert(COND) /* C11 or later */
As both are declarations, I don't think you'll end up in a situation where one is valid and the other isn't - but I could be wrong, and I suspect it would rarely matter in practice anyway.

Re: Lesser known tricks, quirks and features of C

#40

Never quite understood why compound literals are lvalues, but fine, whatever, I guess, it's so that you can write "&(struct Foo){};" instead of "struct Foo tmp; &tmp;"... which, on a tangential note, reminds me about Go: the proposals to make things like &5 and &true legal in Go were rejected because "the implied semantics would be unclear" even though &structFoo{} is legal and apparently has obvious semantics.

It's useful when a function has a out or in/out struct parameter whose value at the end you're not interested in. Or in functions where the struct is an input parameter, but they return it as a return value too, which you can then assign to a pointer variable or immediately pass to another function.

Note that the struct values thus created have longer lifetimes than temporary C++ objects created directly inside the argument list of a function call.

Post reply on HN