From an information theoretic point of view, making 1 out of 256 values of each byte unusable as the content of the string, is an overhead linear in the size of the string, not constant.
From an information theoretic point of view, making 1 out of 256 values of each byte unusable as the content of the string, is an overhead linear in the size of the string, not constant.
I like to think of bash / sh as just a job control system. It enables you to setup process pipelines. Everything is just processes and files (streams). Variables only serve as programs arguments. Since program arguments are also null terminated, variables containing null bytes just make no sense.
(Of course it gets dirty as soon as you feed the output of a job into a variable, for example. I think that isn't even defined by POSIX for non-text streams).
This is why it surprised me when I realized (without having thought about it) that variables can't contain null bytes. It made my quick id3 tag parsing script a bit trickier to write, since I could no longer just use read(1P).
1/(log2(256)-log2(255))
Assuming 8-bit char, at 1417 chars, zero terminated string overhead is 2 chars.
For 255 characters you lose 9.4 bits which is bigger than the cost of an 8 bit size field.
For 65535 characters you lose 378 bits which is much bigger than the cost of a 16 bit size field.
On the other hand you have only one string type for arbitrarily sized strings and most strings are short.
What would really be needed to be more space efficient for short and long strings is a size field with a variable length encoding. E.g. 1 byte for string lengths up to 64, 2 bytes for string lengths up to 8k, etc.
It's just decoding that requires pipeline busting branches. Well, I guess it's fine if you take branch mispredict for the large string case.
Maybe 1 byte with highest bit zero, 0-127, 2 bytes for 128-32767, etc?
The irony is of course now we have variable length encoding for the string size...
I think just using size_t instead makes more sense than saving a byte or two per string. Memory is cheap, but CPUs aren't getting much faster.
When size is an issue and nothing else prevents it either, just LZ4 (or similar memcpy order of magnitude speed compression) the string.
Yes, "size_t" should be just about right for everybody except the guys who _need_ to program in C/C++ and Assembler due to the hard requirements of their systems. Not very many people but very important systems.
Example: a string with 0 character has a length of 1 (it contains NULL), a 100% overhead. A string with 1 character has a length of 2, a 50% overhead. It gets better with larger strings.
Strings that can't make use of 0 have to be a small constant factor longer to store the same entropy, because each byte can only store log_2 (255) ~ 7.994 bits, instead of log_2 (256) = 8 bits.
Of course, if you are storing printable ascii characters only, that doesn't matter, since you are using far less than 256 possibilities per byte, and so don't care that some of them unused onces are used for in-band signalling (https://en.wikipedia.org/wiki/In-band_signaling).
As vardump points out in another comment, that's equivalent to 1 in 177 bytes.