8 Comments
1hEdited

If you're curious about my remark that the function typedef is useless, it's because you can't use it for definitions, just for declarations. You can do this:

typedef int functype(char* x);

functype myfunc;

...and it's essentially equivalent to:

int myfunc(char* x);

...but then you still need to define myfunc() "manually" by restating the parameters and the return value. This won't work:

typedef int functype(char* x);

functype myfunc {

puts("Hello world");

}

Expand full comment

"Three expressions are still required by the compiler, but in C, there is an implicit semicolon after a function definition (void _() { })."

No, there's no implicit semicolon. The syntax for a for statement (as of C23) is:

for ( expression[opt] ; expression[opt] ; expression[opt] ) secondary-block

for ( declaration expression[opt] ; expression[opt] ) secondary-block

The second form allows a declaration (typically something like "int i = 0;" in place of the first expression. But there's no semicolon after the "declaration" term in the second form -- because most declarations provide their own semicolons. For example, "int i" is not syntactically a declaration, but "int i;" is.

gcc appears to be treating a function *definition* as a *declaration*. As far as I can tell, that's incorrect (though of course gcc can do anything it likes as an extension).

There was a change in this area between C17 and C23. C17 has a constraint: "The declaration part of a for statement shall only declare identifiers for objects having storage class auto or register." C23 dropped that constraint.

And even if we assume that a function definition is a declaration, the program still violates a constraint. If you compile with "-std=c23 -pedantic-errors", gcc complains "error: ISO C forbids nested functions".

Expand full comment

Ah, yeah. I saw that part of the spec after discussing this example on Mastodon beforehand. But I explained it a lot worse than you did. By "implicit semicolon", I meant that a function definition doesn't require an explicit semicolon at the end. But that's a boneheaded and inaccurate way to express it.

Thanks for a proper analysis. I edited the text to better capture the gist of this, I think.

Expand full comment

Have you looked at Duff's Device? It weaves a do/while loop into a switch statement. It's the earliest example of C language abuse I learned about (and it wasn't theoretical, Duff actually used it as an optimization).

https://en.wikipedia.org/wiki/Duff%27s_device

Expand full comment

Delightfully ç̶̼͇̘̱̫͋̂̇u̷̧͕̻̤̍̀̽̀̆͜r̸̪̦̣̥̣̆̈́̉̒̔̐̓ș̷͓̯̭͈͈͕̃̇ĕ̶̡̙̫̽͊̔̄ḑ̸̢͖̦͎̱̦̆. Love-hated it!

Expand full comment

Totally degen, loved it :) How come you are so familiar with all those arcane obscure specifications of the C standard? Had you been a business lawyer, you would be filthy rich right now, combining arcane loop-holes ad absurdum to get anything.

Expand full comment

I think the basic explanation is that I write a fair amount of C, but almost all of it recreationally, so I have time to pause and wonder "what would happen if I do *that*"?

Expand full comment

Once again, I'm learning new things about C! I got the typedef, but was unfamilar with either the GNU extension for needless puts declarations or the C99 BASIC feature :-) TIL! This series is fun, I'm looking forward to the next installment.

Expand full comment