At first glance, it appears to be a length-based string with a maximum capacity (alloc). In that sense, it's similar to the flexible array member approach where you can use it as a fixed-capacity buffer rather than as a fully dynamic array.
Personally, I'm not a fan of this design because it blurs the distinction between different string types. In my experience, this kind of approach is mainly useful when you're not using arena allocation. That said, it certainly has its place in specific situations, just not my preferred default for common use cases.
I had always wondered why they weren't done this way in the first place. I mean, I get it, every byte counted, but how many really short strings did your program have such that an extra few bytes made or broke your memory budget? And meanwhile every clock cycle also counted, and you're using a lot of them to do things that you have to do a lot, or else you're just allocating an int to store and reuse the length value anyway...
Anyway maybe I was basking in the luxury of multi-megabyte(!) RAM but my very first question was "why doesn't it just store the length".
To be fair to them, when C first came out, the machines people were using were mostly 8-bit or 16-bit. You can see how they might have thought: instead of storing that byte next to the pointer, why not just put it at the end?
The latter means you need to store only one extra byte for the string, no matter how many pointers reference it. The former could easily compound, since you might have an array of strings, store them in a struct (then have an array of those or another struct containing them), or pass them to functions.
Another example: Git implements and uses `strbuf` internal library to better deal with C-strings that you should use (see its ContributingGuidelines).
https://github.com/git/git/blob/master/strbuf.h
At first glance, it appears to be a length-based string with a maximum capacity (alloc). In that sense, it's similar to the flexible array member approach where you can use it as a fixed-capacity buffer rather than as a fully dynamic array.
Personally, I'm not a fan of this design because it blurs the distinction between different string types. In my experience, this kind of approach is mainly useful when you're not using arena allocation. That said, it certainly has its place in specific situations, just not my preferred default for common use cases.
I had always wondered why they weren't done this way in the first place. I mean, I get it, every byte counted, but how many really short strings did your program have such that an extra few bytes made or broke your memory budget? And meanwhile every clock cycle also counted, and you're using a lot of them to do things that you have to do a lot, or else you're just allocating an int to store and reuse the length value anyway...
Anyway maybe I was basking in the luxury of multi-megabyte(!) RAM but my very first question was "why doesn't it just store the length".
To be fair to them, when C first came out, the machines people were using were mostly 8-bit or 16-bit. You can see how they might have thought: instead of storing that byte next to the pointer, why not just put it at the end?
The latter means you need to store only one extra byte for the string, no matter how many pointers reference it. The former could easily compound, since you might have an array of strings, store them in a struct (then have an array of those or another struct containing them), or pass them to functions.