Yeah, if we only used strings marked with 2-byte integers, everybody would have been happy, because 64kb string is enough for everyone. (And let's be realistic, nobody sane would have chosen 4-byte string length back in early 70s.)
So, if we went down the pass, what will we have? All the fun of having "legacy" APIs that seem to work but internally only accept strings up to 64kb length and mysteriously chop off excess bytes when you least expect it. It's Y2K problem all over again.
And just when you finally think you're over with it, memory is cheaper again, size_t is 64bit, and someone invariably wants to store a binary blob >4G as string. Fun time again.
Have we forgotten how much trouble we went through in the 90s to handle memory in x86 "640k is enough for everybody" architecture?
This is similar to the "kill Hitler" time travel joke [1], it's easy to say things would be better but all we know for sure is that they would be different. Instead of `char` we'd have strings that were `struct` and we'd STILL have a ton of different string formats because of lengths and character formats. (Bonus problem: are the lengths in bytes, or in chars?)
That's exactly equivalent to having a "size" parameter with the same size as the pointer, except you have to use a substract instruction when you want to get the length of the string, so I'd say it's inferior to just storing the length of the string.
For instance, if you copy a string you also have to update the end pointer instead of just copying the size attribute in bulk. And you get the same disadvantages of non-portable strings, different representations depending on the architecture/endianess etc...
I completely agree with the OP, there's no perfect solution. If addr + len was truly superior I'm sure we'd see
struct string { long len; char s[]; };
or for your version
struct string { char *endptr; char s[]; };
everywhere. And the C standard library would have evolved along with it.
Out of the top of my head the only thing that makes '\0' terminated strings special in C is that it's the way string literals are represented. It would be trivial to recode all of string.h using addr + len instead of nul terminated.
That's exactly equivalent to having a "size" parameter with the same size as the pointer, except you have to use a substract instruction when you want to get the length of the string, so I'd say it's inferior to just storing the length of the string.
Except that it has the important property that the (effective) length descriptor, being a pointer, would necessarily "grow" over time (across generations of machines, e.g. 16 bit -> 32 bit, etc.) and would thus never impose any artificial restrictions on string length.
Out of the top of my head the only thing that makes '\0' terminated strings special in C is that it's the way string literals are represented. It would be trivial to recode all of string.h using addr + len instead of nul terminated.
exactly, anywhere you would have
if(str[i] == NULL)
you replace with
if (str.s + i == str.end)
And, of course, I'm sure its completely safe to treat something as a pointer but explicitly set it to memory you don't own (i.e. just past the end of the string). I guess we could point to the last byte and doom everyone to inevitable off-by-one errors in string length computation.
it should hve made it easier actually, because with pointers you are usually just doing addition subtraction, and everything should be independent of the acutal value of the pointer.
Comments
Yeah, if we only used strings marked with 2-byte integers, everybody would have been happy, because 64kb string is enough for everyone. (And let's be realistic, nobody sane would have chosen 4-byte string length back in early 70s.)
So, if we went down the pass, what will we have? All the fun of having "legacy" APIs that seem to work but internally only accept strings up to 64kb length and mysteriously chop off excess bytes when you least expect it. It's Y2K problem all over again.
And just when you finally think you're over with it, memory is cheaper again, size_t is 64bit, and someone invariably wants to store a binary blob >4G as string. Fun time again.
Have we forgotten how much trouble we went through in the 90s to handle memory in x86 "640k is enough for everybody" architecture?
This is similar to the "kill Hitler" time travel joke [1], it's easy to say things would be better but all we know for sure is that they would be different. Instead of `char` we'd have strings that were `struct` and we'd STILL have a ton of different string formats because of lengths and character formats. (Bonus problem: are the lengths in bytes, or in chars?)
[1] http://www.tor.com/stories/2011/08/wikihistory
You can have a multi-byte chained marker.
Use the first 7 bits of the byte as significant digits, the last bit as a boolean (the next byte is String payload or another byte for string length).
https://developers.google.com/protocol-buffers/docs/encoding...
Just store a pointer to the first character and a pointer to the last one. to get the length you just subtract the two.
That's exactly equivalent to having a "size" parameter with the same size as the pointer, except you have to use a substract instruction when you want to get the length of the string, so I'd say it's inferior to just storing the length of the string.
For instance, if you copy a string you also have to update the end pointer instead of just copying the size attribute in bulk. And you get the same disadvantages of non-portable strings, different representations depending on the architecture/endianess etc...
I completely agree with the OP, there's no perfect solution. If addr + len was truly superior I'm sure we'd see
or for your version everywhere. And the C standard library would have evolved along with it.Out of the top of my head the only thing that makes '\0' terminated strings special in C is that it's the way string literals are represented. It would be trivial to recode all of string.h using addr + len instead of nul terminated.
Except that it has the important property that the (effective) length descriptor, being a pointer, would necessarily "grow" over time (across generations of machines, e.g. 16 bit -> 32 bit, etc.) and would thus never impose any artificial restrictions on string length.
exactly, anywhere you would have if(str[i] == NULL) you replace with if (str.s + i == str.end)
And, of course, I'm sure its completely safe to treat something as a pointer but explicitly set it to memory you don't own (i.e. just past the end of the string). I guess we could point to the last byte and doom everyone to inevitable off-by-one errors in string length computation.
I love this solution, but it probably would have made the move from 32-bit to 64-bit harder.
it should hve made it easier actually, because with pointers you are usually just doing addition subtraction, and everything should be independent of the acutal value of the pointer.
That's exactly what I was thinking: a design based on a 16-bit length field would have been even more of a nightmare to migrate to 32, then 64 bits.
Like what Churchill said about democracy: NUL-terminated is a terrible solution, but it beats whatever's in second place.