I would like to add one to the two reasons that User-12277366872757659323 has mentioned:
3.I have to work at the abstraction level of C, but I want to write a correct and reliable program in a modern language
I think there is an excellent candidate, and that is Rust.C and Rust have very great similarities. And not because the compiler is good, but because actually the model of the language is very close to C:
- Structs, Arrays, Pointers, Functions, Enums.
- No object orientation in the Java/C++ style.
- No automatic memory management.
- No exceptions.
- No significant runtime system, can run without operating system and standard library.
- Binaries can be easily linked to other binaries.
- Rust has traits and generics to enable abstraction.
This means, for example, that operator overloading is implemented without incurring run-time costs.
This means that Rust can intercept data races, double frees, some memory leaks, and even invalid access to shared resources at compile time.
But it is extremely useful to manage dependencies on libraries, for example. Cargo is very powerful, but of course you can also use rustc directly, e.g. as part of a larger build system.
Again, there are no runtime costs, but this is an extremely comfortable feature.
They are like Enums in C, except that any value can carry data. The equivalent in C would be a tagged union.
That is why it is called “hygienic”. The macro system goes beyond pure text substitution as in C and can, for example, modify the syntax tree.
All in all, you see one thing above all else: I’m obviously a fanboy.
I wrote a blogpost a while ago highlighting a few core aspects of memory-safe programming in Rust and C (spoiler: of course Rust gets away with it…):
In order not to turn completely away in enthusiasm, finally the cold shower of reality: Rust is MUCH more complex than C, and even if the compiler likes to try to help, it is sometimes difficult to formulate programs so that they fit rustc.That’s why I call rustc the Rust Complainer. A simple linked-list implementation only provides the compiler with an explanation of why it doesn’t work and a suggestion on how it would work. Oh, where we’re talking about the compiler: sometimes it’s really slow. Somehow, he has to work out all the guarantees that Rust makes possible. And the tooling around an IDE is still in the works. It will be some time before it gets really good (but it’s only a matter of time).