There is no perfect language, C just seems the best for me to get job done.
This is a silly argument.
For array bounds checking, if you want it, just a write a structure with buffer length and a getter setter and it is done. People complain this write zillions of getter setters in other languages but just choose to complain in case for C.
It's so easy, yet buffer overflows remain the #1 problem in shipped C code.
> For all small strings that just locally it serves its purpose nicely.
Not really. Whenever I review other peoples' C code, I look at their use of strlen/strncpy/strxxx functions. They're a rich source of bugs, and I'll usually find one in it (usually an off-by-one error). They don't have to be large strings, either, to be slow.
You are saying C string is slow, I am telling you short local strings are not slow, please tell me why it is slow in that case?
I used (Wirth's standard) Pascal in our compiler class in college. String handling was actually pleasant in Fortran-77 on VMS, so I figured pure Pascal had the worst string handling of any language -- until I started programming in C. I finally made peace with C strings, but a couple of decades later, Forth said to me, "Here, hold my beer." I wrote some Forth-word equivalents of some of the C Library string functions to make my life a little easier! :)
In D we call them dynamic arrays. They could be called length-delineated strings.
1: https://en.wikipedia.org/wiki/String_(computer_science)#Stri...
Just record it once
I made a proposal to fix this in C, but it went nowhere:
Another trouble with two variables is there's no obvious connection between them. One can be modified without the other, etc.
> Thankfully, many exist, so this is a non issue
Many string libraries that are incompatible with each other. This is a huge issue. (I myself made many C string libraries. It's not so easy. Try it.)
The language extension I proposed for C is the same one D uses. D has had it for 20+ years, and it has proven very, very satisfactory.
If you want automatic bounds checks, then C is not the language for you.
> This is a huge issue.
Could you give an example where it's a huge problem? I'm probably limited by my experience. All of the codebases I've worked on used a single string library. When passing externally/to other libraries, boring C interfaces were used, then those libraries do what they wish from there. The string libraries I've used were mostly, deep down, just structs, with a length member, char pointer member, and encoding stuffs. Passing to the other library almost always ended up just being those member values being passed as arguments to a function, which were copied to the nearly identical structs of the other string library.
So you use a translation layer. Sorry, I just don't like them, but if you're fine putting these on all your interfaces with other libraries, well, what can I say? :-)
> If you want automatic bounds checks, then C is not the language for you.
I would reframe that as: "if you're ok with buffer overflow malware injection, then C is the language for you!" Nobody has yet figured out how to stop that.
The sad thing is it's so fixable with just a minor, compatible change to C.
Write manual bound checks and good code in general? Granted you won't be able to catch every vulnerability, but at some point other vectors are so much easier to exploit that you won't have to worry about these anymore.
I promise I'll write good code from now on. Scout's honor.
40 years of C buffer overflows argues that doesn't work.
There's very little difference in C between a character string, an array of Bytes, or even a struct of appropriate size. Other than the types and other user friendly (relative to assembly) features that C adds. This is deliberate; yep, it makes working with text harder (and maybe slower) than is necessary, but C doesn't assume that text is something you ever need to represent in your programs by default. So if you need to work with a lot of text, you should find a library for it, or write a library for it.
C isn't designed to be fast (though it often is). It's not designed to be safe (though it also often is). It's designed to be extremely precise, like a hardware description, or a good maths paper.
Some people like that precision. More often, people need that level of precision (see Linus' comments about C over C++ in the Linux kernel).
For someone of his computing calibre, I found his take on C++ surprisingly... immature. He never truly justifies exactly why he feels C++ is bad in his rants[0][1]; furthermore, he resorts to rather poor logic, which boils down to essentially C++ is bad because the programmers using it are bad.
Perhaps when he did attempt to use it, C++ was equally as immature, and the tooling and compilers were sub-optimal, and there was no RAII, nor std::algorithm, nor any of the niceties available with C++11 (it got better still with C++20's concepts, ranges, std::format, modules, etc).
I daresay that C++ is equally as precise (honestly, I'm not quite sure how to parse this in context) and perhaps even fills in the gaps where the the programmer's intention and their code diverge.
[0]: https://lwn.net/Articles/249460/
[1]: https://developers.slashdot.org/story/21/04/17/009241/linus-...
For the record, I attempted Rust. While it looks nice, I am personally more partial to the by-default freedoms that C++ gives, together with judicious use of sanitisers. If not a systems language, then I default to .NET.
This is really bad!
> It's designed to be extremely precise, like a hardware description.
This is absolute nonsense. There's far too much undefined behavior in C for it to be described as precise with a straight face.
More generally, C's lack of memory safety has been directly responsible for innumerable vulnerabilities and trillions of dollars in costs to society. It is unacceptable and irresponsible to start a new project that's meant for public use in C in 2022.
If you're a hardware designer building a microcontroller for a gas heater, you can just target the 'C' model, and you can have a high degree of confidence that anything defined by C will work.
This isn't the case for say Python, since lots of behaviour is defined abstractly in terms of API's and program behaviour (what we want the programmer to worry about), not in terms of memory allocation, and register widths etc. That a hardware designer can design to.
Counterpoints:
1. 0-terminated C strings are slow. There's the constant need to scan the string to determine its length. Taking substrings requires making a copy. Yes, you can manually do length delineated strings in C, but there's no support for it in the language, it's error-prone, and doesn't interface with anybody else's C code.
2. One thing I've noticed over decades of using C is that it's very brittle. What that means is, once an algorithm is selected, it is never changed because it's too hard to refactor the code. (For example, changing a reference type to a value type means changing all the -> operators to .) This means C programs tend to get stuck in a local optimum of inefficient data structures and algorithms.
3. No array bounds checking, leading to a lot of time lost debugging the #1 programming bug in shipped C programs.
If you're doing RAII in C, you're more than ready to move to a more powerful language.