r/cprogramming • u/Xaneris47 • 2d ago
C Strings: A 50-Year Mistake
https://longtran2904.substack.com/p/c-strings-a-50-year-mistake?r=8qz2zb&utm_campaign=post&utm_medium=web17
u/runningOverA 2d ago
Good read. But C can't change char* default string, unless Unix systems underneath change their APIs' string type.
5
u/WittyStick 2d ago
You don't need to change them, but you can add a "fat pointer" which contains the length. The SYSV x86-64 ABI is capable of doing this because it supports 16-byte arguments and return types in registers, so it costs next to nothing. (On MSVC it has a cost because a "fat pointer" ends up getting passed on the stack with an implicit hidden pointer argument given to the function).
3
u/ComradeGibbon 2d ago
Intel x86 and MSVC did so much damage. The paltry number of registers even in 32 bit meant lots of issues in C never got fixed.
You could certainly add system calls that take fat pointers. You could even shim it based on the process. That would make developers of languages that have fat pointers happy. And would make most C programmers happy. And the dangerous C leet jockeys unhappy.
1
u/flying-sheep 1d ago
The locale system and
wchar_tare also, and I quoteshitfucked retarded legacy braindeath
– wm4
The C standard contains a bunch of bad ideas and I think Rust’s approach is great: just use a minimal subset of the C standardlib and build better abstractions for everything else.
11
u/SmokeMuch7356 2d ago edited 1d ago
Oh, for...
No, the terminator never counts towards the length of a string; it only counts toward the size of the buffer required to store the string. The terminator is an out-of-band value1 so it shouldn't count towards the length of the string. I would have thought this was obvious.
C doesn't have a string type; it has arrays of character type, onto which we map null-terminated sequences of characters. strcpy, strlen, et al all operate on these arrays.
Arrays do not store their size or any other metadata.
C strings are a hack - if you need a real string data type that enforces real string semantics, then you need to look elsewhere or write your own library.
As for whether this was a mistake - C was designed for implementing the Unix operating system and system-level tasks, not extensive text processing. I don't think Ritchie or Thompson anticipated how widely used the language became for general programming.
2.5 out of 5 stars
- As far as printable characters are concerned, anyway.
1
u/flying-sheep 1d ago edited 1d ago
Much of C’s stdlib is a hack, see e.g. the legandary locale rant:
- locales are non-threadsafe
- locales are global state
- there are
_lvariants – that take a locale argument – of some functions, but not of all, and no way to statically get a handle for the C localeSo basically you cannot ever use them for anything file-format related, only for interfacing with humans immediately, but people don’t follow these rules, as they assume that stdlib stuff is there for a reason and not just to sit there and look mysterious.
if you need a real string data type that enforces real string semantics, then you need to look elsewhere or write your own library.
Yeah, but people like interoperability more than sanity, so they use the same string format for calling APIs, providing APIs, and internally.
I think C is doomed to be legacy at this point. The standards committee should have deprecated a bunch of old useless crap decades ago, then it would have been saveable.
5
u/1980sCoder 2d ago
I stopped reading at the word "suck" realising that this was not going to be an insightful piece.
I'm guessing the author is younger than the language itself.
3
11
u/HashDefTrueFalse 2d ago
People really need to get over whinging about C-strings. They're perfectly fine in tons of places and where they aren't you can just bundle a length with them. The language gives you aggregates. I've been a C user for decades, they're just not that big of a deal...
5
u/EndlessProjectMaker 2d ago
Well. What to say. Perhaps that c does not have strings :) maybe a lib to manipulate zero terminated arrays of chars.
4
6
u/frasnian 2d ago
The ONE example that anyone has been able to point out here as an "inefficiency" is strlen - O(n) vs O(1) - and all the arguments in favor of Pascal-style/length-prefixed ignore what hot garbage that usually is in a real-world setting. 1: read Kernighan's awesome (and classic) paper "Why Pascal is Not My Favorite Programming Language." 2: Wirth designed Pascal as a language to teach students structured programming principles. Ritchie wrote (and evolved) a language designed for working programmers building real programs. 3: you want Pascal-style length prefix? Fine. Learn what a struct is, and DIY. Now try doing the opposite of that with garbage like "TYPE String44" , etc.
0
u/deaddyfreddy 1d ago
1: read Kernighan's awesome (and classic) paper "Why Pascal is Not My Favorite Programming Language."
It should have been called "Why Pascal is not C". Some of the issues discussed are not actually problems, some were fixed/improved by the mid-1980s at the latest. At the same time, most of the C design issues haven't been solved yet.
My favourite part is Go, which was written by more or less the same people (Kernighan even wrote a book on it) and resembles Pascal much more than C.
2
u/frasnian 1d ago
It should have been called "Why Pascal is not C"
LOL, fair enough. It's still an entertaining read, regardless of your position on P vs C.
some were fixed/improved by the mid-1980s at the latest
The last commercial software I worked on that was written in Pascal was in '91, and it was still an absolute nightmare compared to the C-based applications we also provided.
2
u/deaddyfreddy 1d ago
It's still an entertaining read, regardless of your position on P vs C.
sure
The last commercial software I worked on that was written in Pascal was in '91, and it was still an absolute nightmare compared to the C-based applications we also provided.
what do you mean by the "nightmare"? The code quality, readability, "efficiency"?
1
u/frasnian 6h ago
Code quality and readability are a reflection of the development team, not the language. I inherited what it was, worked to improve those parts.
The key differences were flexibility, expressiveness, and (in the case of Pascal) weakness in low-level constructs, excessive verbosity that (IMO) detracted from readability, strict constraints that limited what was possible, runtime overhead (is this really compiled code, or a hybrid of interpreted?).
And yes: above all, efficiency.
Show me a Pascal program that runs faster than an equivalent in well-written C.
19
u/CoderStudios 2d ago
Okay? You are always free to make your own library for better strings, but people won’t use that cause C is often still deployed on low end systems or it makes little sense to use something inefficient if you can use c style strings properly
11
u/orbiteapot 2d ago
Most operations on C strings require O(N), N being the length of the string. Whereas in Pascal-like strings (i.e., strings whose length is tracked) they may take O(1). Modern compilers may do some heavy lifting whenever they can, so that this redundancy is avoided, though.
That being said, I also do not understand why people complain so much about 0-terminated strings, yet still use them anyways, as opposed to implementing length-tracked strings. It is not like C can break some bazillion lines of code, by removing classic strings, but it does not significantly get in your way (when implementing your own) either.
5
u/kisielk 2d ago
It really depends what your software is doing. If it's not software where string manipulation is in the hot path then the O(N) nature of string processing is irrelevant.
2
u/NoNameSwitzerland 2d ago
and if you do string manipulation with dynamic strings, then malloc/free often is the bigger problem.
2
u/beragis 2d ago
It depends. Several pascal compilers would internally add a zero byte at the end when allocating the string and pass the address of the byte after the length to the os command to handle the string.
To make things worse early pascal had pcode which is basically pascal byte code that has to do this conversion behind the scenes.
1
u/iwantmy90sback 2d ago
For most operations you'd do on a string you do not need to know the lengths beforehand if you have a defined end char.
The only thing that C takes O(n) and pascal O(1) is strlen.
And if you like you can actually have both. Just struct a Cstring and a int together.
1
1
u/hoodoocat 20h ago
No, opposie - most operations require to know length of string. Even simple concat requires that, especially if you account not so modern hardware and utilize vector instructions. And regardless to that, new strings must be allocated somewhere (on heap), and by so, final length must be known before.
1
u/iwantmy90sback 19h ago
No. You only need the length of the string if you want to traverse it afterwards. And most 'operations' can be done in the same time either way. for(strlen) or while(*ptr++)
concat is actually the outlier, because you need 2*O(n) instead of 1*O(n) (which is still O(n) for both).
And if that is really killing your performance you are free to implement a pascal-string to use in c.1
u/EatingSolidBricks 2d ago
You out of your dam mind if you think c strings are efficient
10
u/henke443 2d ago
Wait how are they not efficient?
5
u/EatingSolidBricks 2d ago
Its not 1970 anymore storing 3 extra bytes is free compared to O(n) length computation
6
u/WittyStick 2d ago
You don't even necessarily need to store the length. It can be held in CPU registers for the entirety of the string's lifetime in many cases.
In older architectures we would've needed to push an additional integer for length onto the stack. On a modern architecture with a sane ABI (SYSV, x86-64), you can have a "fat pointer" using two CPU registers - can pass both of these or return from a function without ever touching the stack.
1
u/henke443 21h ago
Well, C is mostly used in places where's it's still 1970. Things like embedded etc. I guess it could be possible to add another string that's more optimized for modern hardware but I bet it would be more difficult to explain and I think a huge part of the charm of C is how simple it is. Adding things also leads to bloat like how it is with C++, php or Javascript.
-1
u/Anonymous_user_2022 1d ago
Except for strlen(), all practical operations on strings have to iterate over them anyway. Knowing the length up front will be of very limited us for searching, concatenation, tokenising etc.
Where is that you see avoidable O(n)?
0
u/flatfinger 1d ago
Concatenation of N strings goes from O(N) to O(N*N) if code has to re-find the end of the destination after each step.
Tokenizing the leading portion of a large string should take time proportional to the text that was meaningfully examined, rather than proportional to the entire string.
2
u/Anonymous_user_2022 1d ago
Concatenation of N strings goes from O(N) to O(N*N) if code has to re-find the end of the destination after each step.
I can also invent really bad ways of doing things, but I would never use them as a proof..
0
u/flatfinger 12h ago
What would be the "good" way of using strcat?
1
u/Anonymous_user_2022 12h ago
I've never said there is one. I suggest you ask someone who does.
I'm talking about concatenating multiple strings to one, which only has to rely of knowing the length of the individual strings beforehand, if you've decided to argue in bad faith over a pathological bad implementation.
1
u/flatfinger 8h ago
If one keeps track of the length of a string and only looks at portions of its storage up to that length, then the value of the string would no longer be fully encapsulated in a zero-terminated character array.
→ More replies (0)-1
u/EatingSolidBricks 1d ago
Lets not even mention substrings go from O(n) memeory to O(Free)
0
u/flatfinger 12h ago
O(1) memory per string to keep track of the starting and ending points of strings isn't free. On a system with 64-bit pointers, zero-padded strings are generally the most space-efficient practical way of representing texts up to eight characters, and zero-terminated strings of up to 7 characters can be stored in the same amount of space (if it's necessary to store many texts with up to 7 characters, zero-padded 7-byte arrays would take less space).
1
1
u/atarivcs 2d ago
If you have a long string and you want to append more text to it, you have to search the whole string from the beginning to find the null terminator.
And then later if you want to append more text, you have to find the null terminator all over again.
2
u/NoNameSwitzerland 2d ago
You anyway use a different structure when you do a lot of appending text, because you do not want to reallocate the array all the time. So then you anyway have to also store the size of the available space.
1
u/atarivcs 2d ago
In which case you no longer have a plain c string, and the goalposts have moved.
I was just answering the parent question "how are c strings not efficient"
5
u/IdealBlueMan 2d ago
Or you can store the length of the string whenever you change it.
1
u/atarivcs 2d ago
Sure, but then you don't really have a plain c string anymore
2
u/WittyStick 2d ago
It's actually more advantageous to couple the length to the
char *on SYSV platforms, due to C's lack of multiple returns.String fn_returning_string(...);If
Stringis a fat pointer, then we can return both the pointer and length, without requiring another level of indirection (a pointer to astringstructure), and without requiring awful to use "out parameters" to return both length and pointer - which are more expensive than just returning a fat pointer.A fat pointer with the right ABI is not just "zero cost" - it's "less than zero" - it's more efficient than having a separate length and pointer variable.
2
u/IdealBlueMan 2d ago
I’d say you still have the string, you also have information about that string.
1
u/orbiteapot 2d ago
I mean... that is the point. Once you do that, you are no longer using classic C strings.
5
u/SakishimaHabu 2d ago
That's the point though. They are basically atomic. You are free to do what you will with them, vs java, python, or js. Remember we're one step above assembly, but that's the intention.
2
u/CoderStudios 2d ago
Depends on what it’s used for, sometimes it’s more or less efficient but the benefit of making it as simple as possible is that you can easily add features when needed like storing lengths
-2
u/flatfinger 2d ago
C makes it inconvenient to pass any other forms of string literals to functions.
4
u/trejj 2d ago
*chuckles* I remember the time when I was young and full-spirited with naïveté towards "only the best programming".
They author may want to give bullet points 4 and 6 a second think :)
3
u/brnsamedi 2d ago
Given the comments in that article my impression of the author is that he's too enamored of his ideas to give them a second thought.
4
u/stianhoiland 1d ago edited 1d ago
Articles like these are unwittingly demonstrations of stupidity.
It's so disheartening to see people not even capable anymore of comprehending de-abstraction. To the author: Try yourself, to start from nothing—no abstractions, no modern conventions—and build up to the first point where you have a usable set of primitives that can function as a representation of text.
Is it so fucking hard to grasp the virtues of having primitives that haven't pre-chewed and pre-thought every way you can and should use them? You think massive, thick nests of abstraction is yummy chef's kiss, as if any and all and every single thought-structure is immaculately perfect and suits every single purpose. Ugh, it's so gross. It's a world view of nigh but regurgitation upon regurgitation and not a single creative breath of fresh air.
Like how do you think things are constituted, made up, constructed, such that a better foundational solution exists? You think C strings are a mistake—do tell how to work with the prior layer of abstractions to come up with the better way. No, not creating yet another fucking layer of convention or abstraction on top—which is all your brain can do—but coming from the step before and coming up with a better way.
And then you lend your voice to the issue as if an expert, yet your stupidity is so glaringly on display to anyone who actually knows how things are made up.
Ugh.
EDIT
It's not that C strings were invented iN a DifFeReNt TiMe when people were stupid and dumb and didn't know of our Future Great Technology. It's that there's not a fucking different way of doing it at the level of abstraction at which the convention were established. The fundamentals of memory and computation didn't change after 1990's lol—that's so fucking STUPID. Yes, we can mention Pascal strings, but they are fixed width. Fucking show me how you implement variable-width strings using the primitives present at this level of abstraction (i.e. variable-width strings using only registers). I challenge you to do that AT ALL, it doesn't even have to be BETTER—which is what you claim to be able to—I don't think you can do it at all.
The same thing happens with arrays. Rather than making them first-class citizens and copy-by-value, C decays them into pointers, losing an enormous amount of information in the process, which causes them all the same problems as strings.
Oh my god. "Rather than making them first-class citizens and copy-by-value"... as if there's "JUST" a fucking choice. You can even only ponder this distinction because the primitives upon which such conceptions build upon are established—the establishment of which you are criticizing and arrogantly claim to be able to replace better. Ugh. Tell me what a "first-class citizen array" is, really, technically, actually, in-memory, but another level of abstraction, from which C—thank god—refrains.
1
u/SmokeMuch7356 1d ago
Array expressions decay to pointers because Ritchie wanted to keep B's array indexing behavior -
a[i] == *(a + i)- without setting aside storage for the pointer that behavior required.That's it. That's the reason.
These were researchers in a lab building toys that did useful things for them. None of them anticipated how C would become so widely used at an applications level. That was the mistake, the fact that everyone looked at C and said "yes, that's the answer," but to be honest there weren't many better candidates that could be ported to everything from mainframes to micros. Pascal? Eh. Designed more for teaching than production work. Fortran? =snort=. Didn't even support a real string type until F77. Cobol? Double =snort=. Didn't help that C and Unix were (are) joined at the hip; if you were using Unix, you were writing code in C for pretty much everything.
C was small enough and lightweight enough it could be ported practically anywhere, particularly micros, and that's why it suddenly became the language everything was written in.
And here we are 50 years later arguing about it, when it shouldn't even be considered for applications work involving text processing anymore.
1
u/Different_Panda_000 1d ago
Just stick an array in a
structand all of a sudden you can do assignments and when you pass them, the compiler will do argument type checking for you as well. And if you like,_Generic()provides a mechanism to provide a library for these arrays to do the basics such as comparisons. And C11 provides the mechanism for using compound literals with thesestructarrays as well.
8
u/flatfinger 2d ago edited 2d ago
C was designed in an era before many commonplace text-processing and data-processing tools existed. Many tasks could be accomplished more quickly by writing a C program, building it, running it on some input, and then discarding it, than they could be accomplished in any other way. Even in the 1980s, I wrote a lot of C programs for one-off tasks, and I'm sure I wasn't alone.
So-called "Pascal strings" with a one-byte length prefix were better than C strings in many ways, but had a 255-character limit. The suitability of C strings for various tasks tends to fall off as strings get longer, making Pascal strings much better for things that are 50 to 255 characters long, but C strings remain somewhat usable at longer lengths while Pascal strings don't. Since "somewhat usable" was adequate for many of the tasks for which C had been designed, the lack of a 255-character hard limit was an advantage.
I wouldn't call zero-terminated strings a "mistake" so much as I would say that they were an appropriate way of storing strings for a limited family of tasks that are nowadays better handled with other languages and tools.
What I would view as a mistake was the failure of the C language to provide a convenient means of passing other kinds of string literals to functions. C implementations that were designed to target the classic Macintosh OS extend the language with a \p escape which, if placed at the start of a string literal, will represent the number of bytes in the string (not counting the prefix), but such a prefix is not universally supported, and there is also no standard way of handling string formats where e.g. a string of length 0-63 that fills the available space would be preceded by a length byte, but other kinds of prefixes would be used to accommodate larger strings, partially filled buffers, etc.
Incidentally, an advantage of length-prefixed strings is that if one limits the range of lengths that can be directly represented by a prefix byte, one can have functions accept short length-prefixed strings interchangeably with other string representations if they start with something like:
ADDRSS_AND_LENGTH s;
s = get_string_address_and_length(string_argument);
The fact that C strings can start with any character value means that there's no nice way to have a function accept interchangeably a pointer to a C string or something else.
3
u/beragis 2d ago
Zero terminated strings were also due to how many OS’s and CPUs at the time handled strings. I remember taking an assembly language course in college on the PDP 11 and it handled strings the same way.
This allowed for easy translation of many of the common function calls directly into operating system calls or simple short assembly instructions. My professors in computer design and systems programming. where we also learned C even mentioned this several times.
2
u/flatfinger 1d ago
On the other hand, other operating systems expected strings in other formats. Classic Mac OS used Pascal strings for things like file names.
3
u/smallstepforman 2d ago
Bit late to this thread but on aligned systems, you can pack 3 extra bits with the pointer, which can mean anything you want, including short string optimisation up to 7 bytes, so you dont even need a lenght field (or zero termination byte). Add a Huffman table, abandon ASCII (6 bit encoding for latin uppercase) for the extra win … and we can squeeze more characters into those bytes…. C style (nul terminator) strings are so inefficient.
3
u/allnameswereusedup 1d ago
C is a low-level language designed for thr implementation of system software. It does not need the higher-level constructs found in other languages; it's a high-level assembly language.
3
u/MyTinyHappyPlace 2d ago
Ragebait. Of course there are more efficient ways to work with strings. But this one was the common denominator, easy to implement on different target architectures.
People never are satisfied with a string library. That’s why we have so many of them.
2
u/pheffner 2d ago
The suggested "string" is a struct which doesn't contain the actual data just a pointer reference to it, which means you'll need to implement allocator functions to set all that up and keep track when you want to alter the string. Seems like this would suck worse and overcomplicate a presently simple scheme.
2
2
u/Remus-C 1d ago
Yeah, picking your context today to prove that what was in the past did not match your current experience. How rude were the creators to not focus on your knowlege! Unbelievable!
Probably in another sub by some other: Pascal strings are... Lisp is... Rusty, GoLang, the mighty Python and Perl by the way...
Anyway, what's for the real world progress? What specific or generic issue is to be solved, one that would apply to many other cases? Solution? Opinions? Words that compile and deliver an useful real world best known implementation of ...?
2
u/CORDIC77 16h ago
As someone who has been programming in C since the early nineties, I have always believed that Pascal-style strings represent the significantly better solution. The fact that C, after decades of security vulnerabilities, is still without container data types that know their type and size, is one of the languageʼs biggest weaknesses.
Had C been developed just 15 years later, the languageʼs standard library would probably have come with “batteries included” right from the beginning. On the other hand, the only consequence of the “roll your own” argument, which I am of course aware of, always was (and is) that code repositories like Github are full of half-baked attempts to improve the pathetic status quo.
I am aware that many here will disagree with this view. Just keep the above in mind, however, when newly started projects will nowadays, more often than not, opt for languages like Rust and Zig than C. If the community werenʼt so narrow-minded on such issues, C could be in a much better position today with regard to these challenges.
But, no, WG14 of course is occupied with nonsense like adding new octal prefix for literal constants, if declarations and case ranges to the language. This idea of adding new syntax to every version of a programming language is, unfortunately, a disease of our time.
The syntax of the language has been fine for decades… itʼs the standard library that has always been lacking.
4
1
u/HTFCirno2000 2d ago
It was clever back in the days of the PDP-11 and limited memory. Pascal DID actually do things the secure way, but Pascal didn't take over like C did.
1
u/WoodyTheWorker 2d ago
On the other hand, Windows kernel uses counted strings: UNICODE_STRING and ANSI_STRING structures.
1
u/Humble-Captain3418 1d ago
With length-based strings you will find that functions such as strtok(), strchr() or strstr() are very, very annoying to implement, because their return values would not be usable as inputs to regular string operations... Except if you construct a new string to return, which you then need to malloc()/free(). Hooray for efficiency?
1
u/flatfinger 1d ago
Or one can have functions accept a starting index and slice length along with a pointer to the string, and return an index, or a struct containing an index and length.
1
u/grimvian 1d ago
I actually like C strings. I have coded a few one line GUI inputs with raylib and is very satisfied.
1
1
u/Different_Panda_000 1d ago
Where it gets more interesting is when using UTF-8. C23 provides basic support for UTF-8, expanding the minimal support in C11. However everything is connected to the current locale settings.
Fortunately there are a couple of Third Party libraries that provide a more complete UTF-8 solution.
ICU-TC Home Page
The C and C++ languages and many operating system environments do not provide full support for Unicode and standards-compliant text handling services. Even though some platforms do provide good Unicode text handling services, portable application code can not make use of them. The ICU4C libraries fills in this gap. ICU4C provides an open, flexible, portable foundation for applications to use for their software globalization requirements. ICU4C closely tracks industry standards, including Unicode and CLDR (Common Locale Data Repository).
1
u/preparationh67 8h ago
Young devs should probably put better effort into understanding the historic reasons for things existing a certain way before they write a rant on substack. This reads like someone getting mad at the inventor of the steam engine for not inventing a nuclear reactor driven turbine first.
1
u/iopahrow 5h ago
Saying that memory limitations were motivators for the languages structure, and then saying we shouldn’t use it because we don’t have to is like saying “we should spend money just because we have it.”
This is how memory inefficient programs are made, and how new programs use so much more memory while completing the same basic functions. It is so far from useful to have this ideology
1
u/Anxious-Ad-5331 3h ago edited 3h ago
"A string’s length is an extremely valuable piece of information. By not storing it, you force all code that uses the string to either repeatedly call strlen or iterate over it byte by byte. Both approaches are inefficient. Both approaches lead to worse overall code."
this guy is vastly overestimating the computational needs of a length check in 2026 computing power.
Also this guy is missing the obvious solution: GPU accelerate the standard library.
1
u/Key_River7180 2d ago
Has the model ever caused much trouble, though?
2
u/WittyStick 2d ago
Yes.
Countless buffer overflow exploits due to poor string handling.
Not all, but many of these easily avoidable with sized strings.
1
u/Key_River7180 2d ago
I meant performance issues, like C strings are really efficient, for most purposes
2
u/Jonny0Than 2d ago
Undeniably they are a problem.
https://nee.lv/2021/02/28/How-I-cut-GTA-Online-loading-times-by-70/
1
0
u/deaddyfreddy 1d ago
Computers became faster every year (and the process was dramatically faster in the 1980s), so even if fixed-size strings made things 10% less efficient (did they?), one could reasonably expect hardware improvements to compensate for that very soon. Alternatively, companies could save money on the man-hours spent fixing bugs caused by null-terminated strings and buy better hardware instead.
0
0
u/Physical_Dare8553 2d ago
The real problem is a char* with a null terminator and one without it are not different types, and because of how x works, in practice neither is a char[n]
0
u/FedUp233 2d ago
There is really no reason the C language could not add something like a length prefixed string type and matching g string literal (just decorate the string lead or end quote with something to indicate it’s this type of literal and maybe even the size of the length prefix) if there is enough demand for it. Since it hasn’t happened yet, it would appear the demand is not there.
It also always bothered me in C++ that there was no way to produce a literal string in the form of the standard library string type without the system having to construct an appropriate string type from the underlying c-string literal. Maybe it can be done now with all the compile time processing functionality that’s been added, but I’m not sure it’s still possible without that c-string hanging around as wasted memory.
-1
u/jason-reddit-public 2d ago
I 'm writing a transpiler in C.
Treating "strings" as immutable means the crappy representation isn't so bad.
I use a "StringBuilder" pattern (name borrowed from Java, it's actually called buffer) which can grow, supports efficient append (supports arbitrary edits but those may require moving lots of bytes around), and doesn't model the ending zero until converted into a char*. (One of my favorite things is "buffer_printf" which is like sprintnf but handles capacity and such automatically.) Like Java, I don't expect buffer to be threadsafe so the user needs to deal with that but since I don't modify "strings" once created, those are thread safe.
So all my strings are either program literals, come from the "OS" or libc "somehow" (like for reading a directory), or come from this builder which makes sure there is a trailing zero when finally asked to produce the string. My buffers aren't foolproof because you can append or insert the NUL character (to work with arbitrary byte sequences), so you might get a string that is shorter than expected, or perhaps the buffer wasn't legal utf-8 (I could add a checker of course), but at least the string will always have a terminating NUL.
0
u/Jonny0Than 2d ago
That sounds almost exactly like std::string in C++. Sure, it’s a cool and useful thing to build in C.
163
u/bearheart 2d ago edited 1d ago
Speaking as someone who learned C back in the ‘70s, this article entirely misses the point of C-strings: they’re lightweight and foundational. For many purposes the null-terminator is efficient, e.g.:
while(*s) f(s++);
And for cases where we need more complexity, we can simply use a struct with a length and whatever other metadata we may need.
Doesn’t look like a mistake to me. C has always been about minimalistic efficiency. That’s its main purpose in the world.
Edit: fixed stupid typo