back

by uecker·2y ago·view on hn ↗
I think I have the opposite opinion. Newer C standards have a very high degree of backwards compatibility. I think we should try to transition code to the current ISO standard and in almost all cases this will just work without problems. In the few cases, where it does not, it is usually for a very good reason.

Now, nobody is stopping compilers from supporting old language modes, but it adds a lot of complexity, not for making the code compile, but for all the diagnostics which are different. If you look at the FE code of GCC, for example, a lot of code is dedicated this. If we could remove all this stuff at some point (which would still allow old code to compile, but one code remove diagnostics for things which were disallowed in earlier standards but are now allowed), then this reduce maintenance burden substantially. And if one really needs those old diagnostics, one could simply go back to an old version of the compiler.

2 comments
I would rather just announce to the compiler what standard version a given piece of code should adhere to (and it's fine if -std=2x doesn't accept older C standards except for header declarations - while at it, please remove the 'inline' keyword from the next C standard ;))

To some extent that's already possible with the "-std=..." option of course, but it would be better to also allow changing the standard version within the same compilation unit (at least if it turns out that including headers written in old C standards can't be supported, in that case I would like to wrap a block of #includes with a 'use c89 { ... }').

Random example for why it is important to allow older C versions to compile: I just made a mid-90's assembler for 8-bit CPUs written in C89 work in VSCode via WASM/WASI without requiring any code changes (and yes I've been looking long and hard for an alternative assembler tool which provides the same feature set written more recently without luck, I even considered writing my own assembler from scratch).

It would suck if I had to port the code base to a more recent C standard just to make it compile, and (if that would be possible) automatically formatting that code to a more recent C version would introduce a hard "before/after" split in version control.

What is wrong with "inline"?

I do not think it is feasible to maintain all language versions in parallel for eternity. What would make porting this code to a newer standard difficult in this specific case?

Inline "encourages" moving implementation code into headers instead of only interface declarations, and the inline feature isn't all that useful anymore with LTO anyway.

It's a good thing to only have declarations in headers, it simplifies parsing with 3rd party tools (to generate language bindings), and speeds up compilation (see the C++ stdlib headers for the canonical "why is implementation code in headers a bad idea" example). IMHO mixing interface declarations with implementation details was one of the cardinal sins of C++.

> What would make porting this code to a newer standard difficult in this specific case?

It's pointless busywork, and it's unclear how deep the changes should go (for instance: does it make sense to move C89 variable declaration from the start of scope blocks to their initialization point just because it might potentially be "safer" but touches half of all lines of code?).

The code demonstrably works as C89, and any bugs that matter most likely had already been fixed decades ago, also doing large scale syntax changes is just noise in version control which makes bug fixing harder (because that often involves diving into the change history).

I fully agree that this is the cardinal sin of C++. I think that C still offers much better encapsulation by using interfaces based on incomplete struct types. While I understand your point regarding inline, there are some comments I would like to make: It is now there and removing it would break existing code. The alternative are often macros, but inline functions where they can replace macros are better and the compiler can decide not to inline when it does not make sense. LTO is an alternative, but does not work across library boundaries, and also has a very substantial compile-time cost.

Compiling with a new language mode does not force you to move variable declarations to the point of initialization, but you would now have the option to improve the code in this way when it makes sense. It is difficult to see this as an disadvantage. My point is that moving it to a new language version would usually not require changes to the code, except where the old modes were dangerous. So I would expect to find serious bugs when doing this.

> ... So I would expect to find serious bugs when doing this.

That's actually a good point hmmm (not in case of this specific assembler, which seems to be quite robust and well-written), and even if there would be serious memory corruption errors lurking, they would be contained because the assemblers runs in a WASM VM.

For projects that are still maintained, a "moving standard" isn't that much of a problem, after all we've been conditioned that every new compiler update adds new warnings which "break" existing code ;)

...there is a certain value in taking a "finished/frozen" project and integrate that into a new project without requiring code changes though.

I'm sure there must be a good middle-ground for C, where obviously bad and outdated language features (starting with leftovers from the K&R era) can be removed without causing too much breakage even on most old code ... but then, why keep 'inline' ;P

Which C++ fixed with modules. Something that most likely C will never have.
> Something that most likely C will never have.

...rather, doesn't need. C++ modules just (potentially at least) fix a problem that C++ created in the first place (exploding build times because of complex template code in stdlib headers).

Also, I have yet to see clear indications that C++ modules drastically improve build times in real world projects.

Back when I had to develop in C, I would routinely wait for 1h builds.

The trick to make them faster is the same as with C++, never compile everything from source unless required, this includes template code for common type parameters.

As for compile times see Microsoft Office modules migration, or that VC++ import std in C++23 is faster than a plain #include <iostream>.

> I think we should try to transition code to the current ISO standard and in almost all cases this will just work without problems. In the few cases, where it does not, it is usually for a very good reason.

Microsoft's C compiler did not support C99 until something like 15 years after the standard came out (and reportedly (according to colleagues who use that platform) still doesn't support certain features of it).

It happens with surprising frequency that someone reports to the sqlite project that The Latest Version no longer works on their pre-2005 environment and they'd like to see it patched to work there.

My point is: users of a given platform might not be able to use The Latest Stuff (or anywhere near it, for that matter) because their OS vendor is reticent, because they have to support an old platform which is not targeted by newer tools, or for whatever other reason.

> Now, nobody is stopping compilers from supporting old language modes, but it adds a lot of complexity, ...

i don't doubt that, and i do sympathize with the maintainers. i'm not saying they should never ever remove C89 support, but if they do then there needs to be an alternative, like a fork of the last compiler version which supported it, maintained at least to the extent that the rare genuine compiler bugs can be resolved.

Microsoft considered C done, as clarified by Herb Sutter.

https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-an...

They only kept updating their C support to the extent required by ISO C++ requirements, and some key customers.

Anyone else still dependent on C was suggested to use clang, this is also why clang is part of Visual Studio compiler suite nowadays.

Around the time the Microsoft <3 Linux stuff started, they decided to backtrack on this matter, and started updating their C support, however since C11 made a couple of stuff from C99 optional, they decided to skip on those.

VLAs have anyway been proven a rich source of exploits, to the extent Google has sponsored the work to clean up the Linux kernel from all uses of them.

https://www.phoronix.com/news/Linux-Kills-The-VLA

The VLA security problems are a bit of a myth. In the kernel it may be some problem, but with stack clash protection (which one should activate anyway) there isn't really a inherent security issue anymore. The code quality improvements of using VLAs usually make it worth using them IMHO.
A myth that was worth every penny fixing it, as per Google.
Do you have link? BTW: I was tangentially involved in this effort...
It was on my original comment.

Also there were a couple of talks from Linux Plumbers Conference given by Kees Cook, if I recall correctly.

I now regret helping with this effort, since people use it as arguments against using VLAs in general, although in my opinion this is clearly the wrong conclusion outside of the kernel. VLAs are basically always superior to the next best alternative: They are safer than alloca() (and standard's compliant), they are faster than heap allocation (and similar safe), and use less stack and allow better bounds checking than a worst-case fixed-size arrays on the stack (but are slower).
Microsoft declared C dead and wanted that everybody transitions to C++. Luckily this changed a bit and MSVC now supports newer standards. Also there are now other alternatives on Windows. So I do not think there is a good reason to put everything on standstill anymore. C needs to evolve and old code must be maintained. For me, this this means that code should be transitioned to newer standards. In no other industry would it be acceptable to ignore current industry standards. Now, I do understand that some projects do not want to use newer features for portability reasons. But this does not mean that they couldn't be compatible with a newer ISO C modes as well. Being compliant with C 17 does not necessarily mean one has to use new features.