Rendered at 08:27:01 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
chasil 6 hours ago [-]
I just rebuilt a core program that talks to my UNIVAC OS2200 CITA and my VAX ACMS from Linux.
I built this first as a 32-bit binary, and there was noise that I had to cut with a substr function.
In the rebuilding with my MinGW 64-bit Windows cross compiler on Oracle Linux, I had to mine function prototypes out of all the code for exactly this reason.
'for those unaware: c89 has a cool "feature" where, if you try to call a function which doesn't exist, rather than erroring out, the function is implicitly declared as a function with unspecified parameters returning int.'
I'm not testing this, because that is agony.
I'm leaving them a working build, and retiring this month.
This code was written by the living and the dead, and my stewardship is finished. I do not envy the poor soul who must test this.
It was ashes when I excavated it myself. A hat tip to those who have gone before.
geocar 10 minutes ago [-]
> I had to mine function prototypes out of all the code for exactly this reason.
The program that does this is called cproto and it was available back on comp.sources.unix as early as 1989 (if you find yourself with a time machine) and these days is available on nearly every Linux distro.
pjmlp 50 minutes ago [-]
That feature was already present in K&R C, C89 function prototypes were actually taken from the C++ standardisation process back into C, while keeping that behaviour in place.
ronsor 4 hours ago [-]
Implicit declarations are a classic!
Current GCC and clang error on them by default now, but that's a rather recent change.
bellowsgulch 4 days ago [-]
All the weird stuff I have read about C or C++ doing over the years could be summed up with “Well… don’t do that.”
Like almost without fail. I can’t even think of how you’d end up in a scenario like this because a compiler would complain before letting you use an undefined implicit declaration.
I’m not going to defend all of the ones C(++) has but stuff like deref’ing null or integer overflow or out of bounds access has its roots in sanity, it just looks insane today. There are tools for many/most of these and if you’re not using them you’re doing it wrong.
mjevans 4 hours ago [-]
I sum it up with: give me an error message rather than undefined or unintuitive behavior.
bitbasher 4 days ago [-]
That doesn't make it any less interesting :)
stinkbeetle 1 hours ago [-]
It does. Some people would still be interested but lots of people would not. The net interestingness would certainly decrease.
Joel_Mckay 4 hours ago [-]
Most people build C in g++ before gcc, as it tends to have a better chance of catching most oddities. Then run it past valgrind to double check if something looks suspect or is slowly leaking. =3
flohofwoe 2 hours ago [-]
> Most people build C in g++ before gcc
That's not possible for 'standard C' though, only for the separate language that's called "the common subset of C and C++". E.g. it works more or less by accident for some specific C code that predates C99, but even that is built with C++ semantics (which has many subtle and some not-so-subtle differences to C semantics).
Instead of trying to build C in C++ mode, turn all the warnings to 11 (and also include warnings that aren't in -Wall -Wextra, like -Wsign-conversion).
pjmlp 38 minutes ago [-]
Agreed, the point of divergence is already C89, not C99.
The C++ compatibility with C, is "As Close as Possible to C, but no Closer", meaning supporting C should not break the stronger type checking or the improved type system C++ has over C.
As such, besides C89 original differences, compatibility has only been added for C features that don't clash with C++ approach to the same problem, and while the C++ standard library keeps up with ISO C, it also does so taking into consideration C++ features for the implementation of said library functions.
The 'g++ -x c ...' will parse portable source just fine (compiles code as C, but links against libstdc++), and tends to identify poorly structured code with verbose checks. If people default to gcc file extension inference, than it is likely to remain silent when people do something silly.
That's a nice bit of understated 90s design right there
tosti 2 hours ago [-]
90s design had frames, tiled backgrounds, low contrast and lots of different font colors.
The "nice" sites didn't style much at all, which usually meant the default serif font was used.
kevin_thibedeau 7 hours ago [-]
> f[...]
It is illegal to perform pointer arithmetic on function pointers. They are not necessarily interchangeable with data pointers. Clang is wrong.
phire 6 hours ago [-]
In c89, there doesn't seem to be any distinction between pointer to functions and pointer to data.
Do you know what c89 does explicitly say is undefined? Any pointer arithmetic at all (or array subscripting) for pointers are not pointing to a member of an array. It's already invalid to do pointer arithmetic a pointer to a struct.
Not that it matters for this. This isn't doing pointer arithmetic, f is simply the identifier for the array of "sizeof(f) ints" that make up the function argument. The identifier is optional for a function declaration.
kevin_thibedeau 6 hours ago [-]
There is a distinction. Lisp machines do not allow function pointers to become data pointers. The C standard accounts for that. Function pointers also have special decay behavior unlike data pointers. You can chain an unlimited number of '*'s and still get a valid function pointer.
int f(int x) { return x + 1; }
int main(int argc, char *argv[]) {
int (*fp)(int) = f;
printf("Answer: %d\n", fp(39) + (****fp)(1));
return 0;
}
phire 5 hours ago [-]
Not sure about later versions, but c89 doesn't seem to forbid casting a function pointer to a data pointer (it does say that casting pointers has implementation defined aspects, so lisp machines aren't out of spec if they fail).
The reason you can chain unlimited ''s is that f isn't actually a function pointer, it's a function designator. Function designators are automatically converted to function pointers in almost every case, but '' is special cased so that indirecting a raw function designator results in another function designator.
Edit: Actually on a closer reading, maybe it does. C89 doesn't explicitly point it out as forbidden or undefined, it simply defines two classes (objects and functions) and only defines a very limited set of valid operations on pointers to functions.
Though one operation that is implementation defined is converting a pointer to an int, and an int to a pointer. So with two steps through an implementation defined path, you have a data pointer to a function.
guenthert 4 days ago [-]
"because the problematic behavior was removed from the standard over 27 years ago, we'll never have closure on what the intended interpretation is."
Obsolete standard turns out to be insufficiently strict, news at 11.
I built this first as a 32-bit binary, and there was noise that I had to cut with a substr function.
In the rebuilding with my MinGW 64-bit Windows cross compiler on Oracle Linux, I had to mine function prototypes out of all the code for exactly this reason.
'for those unaware: c89 has a cool "feature" where, if you try to call a function which doesn't exist, rather than erroring out, the function is implicitly declared as a function with unspecified parameters returning int.'
I'm not testing this, because that is agony.
I'm leaving them a working build, and retiring this month.
This code was written by the living and the dead, and my stewardship is finished. I do not envy the poor soul who must test this.
It was ashes when I excavated it myself. A hat tip to those who have gone before.
The program that does this is called cproto and it was available back on comp.sources.unix as early as 1989 (if you find yourself with a time machine) and these days is available on nearly every Linux distro.
Current GCC and clang error on them by default now, but that's a rather recent change.
Like almost without fail. I can’t even think of how you’d end up in a scenario like this because a compiler would complain before letting you use an undefined implicit declaration.
I’m not going to defend all of the ones C(++) has but stuff like deref’ing null or integer overflow or out of bounds access has its roots in sanity, it just looks insane today. There are tools for many/most of these and if you’re not using them you’re doing it wrong.
That's not possible for 'standard C' though, only for the separate language that's called "the common subset of C and C++". E.g. it works more or less by accident for some specific C code that predates C99, but even that is built with C++ semantics (which has many subtle and some not-so-subtle differences to C semantics).
Instead of trying to build C in C++ mode, turn all the warnings to 11 (and also include warnings that aren't in -Wall -Wextra, like -Wsign-conversion).
The C++ compatibility with C, is "As Close as Possible to C, but no Closer", meaning supporting C should not break the stronger type checking or the improved type system C++ has over C.
As such, besides C89 original differences, compatibility has only been added for C features that don't clash with C++ approach to the same problem, and while the C++ standard library keeps up with ISO C, it also does so taking into consideration C++ features for the implementation of said library functions.
"Sibling Rivalry: C vs C++"
https://www.stroustrup.com/sibling_rivalry.pdf
"C and C++: Siblings"
https://www.stroustrup.com/siblings_short.pdf
"C and C++, a case for compatibility"
https://www.stroustrup.com/compat_short.pdf
Two examples of the library updates,
"C++17 should refer to C11 instead of C99"
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p00...
"C++26 should refer to C23 not C17"
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p33...
Best of luck, =3
https://www.man7.org/linux/man-pages/man1/g++.1.html
https://www.youtube.com/watch?v=X6WHBO_Qc-Q
That's a nice bit of understated 90s design right there
The "nice" sites didn't style much at all, which usually meant the default serif font was used.
It is illegal to perform pointer arithmetic on function pointers. They are not necessarily interchangeable with data pointers. Clang is wrong.
Do you know what c89 does explicitly say is undefined? Any pointer arithmetic at all (or array subscripting) for pointers are not pointing to a member of an array. It's already invalid to do pointer arithmetic a pointer to a struct.
Not that it matters for this. This isn't doing pointer arithmetic, f is simply the identifier for the array of "sizeof(f) ints" that make up the function argument. The identifier is optional for a function declaration.
The reason you can chain unlimited ''s is that f isn't actually a function pointer, it's a function designator. Function designators are automatically converted to function pointers in almost every case, but '' is special cased so that indirecting a raw function designator results in another function designator.
Edit: Actually on a closer reading, maybe it does. C89 doesn't explicitly point it out as forbidden or undefined, it simply defines two classes (objects and functions) and only defines a very limited set of valid operations on pointers to functions.
Though one operation that is implementation defined is converting a pointer to an int, and an int to a pointer. So with two steps through an implementation defined path, you have a data pointer to a function.
Obsolete standard turns out to be insufficiently strict, news at 11.