What advantage(s) of string literals being read-only justify(-ies/-ied) the:

  1. Yet another way to shoot yourself in the foot

    char *foo = "bar";
    foo[0] = 'd'; /* SEGFAULT */
  2. Inability to elegantly initialize a read-write array of words in one line:

    char *foo[] = { "bar", "baz", "running out of traditional placeholder names" };
    foo[1][2] = 'n'; /* SEGFAULT */ 
  3. Complicating the language itself.

    char *foo = "bar";
    char var[] = "baz";
    some_func(foo); /* VERY DANGEROUS! */
    some_func(var); /* LESS DANGEROUS! */

Saving memory? I've read somewhere (couldn't find the source now) that long time ago, when RAM was scarce, compilers tried to optimize memory usage by merging similar strings.

For example, "more" and "regex" would become "moregex". Is this still true today, in the era of digital blu-ray quality movies? I understand that embedded systems still operate in environment of restricted resources, but still, the amount of memory available has increased dramatically.

Compatibility issues? I assume that a legacy program that would try to access read-only memory would either crash or continue with undiscovered bug. Thus no legacy program should try to access string literal and therefor allowing to write to string literal would not harm valid, non-hackish, portable legacy programs.

Are there any other reasons? Is my reasoning incorrect? Would it be reasonable to consider a change to read-write string literals in new C standards or at least add an option to compiler? Was this considered before or are my "problems" too minor and insignificant to bother anyone?

  • 12
    I assume you've looked at how string literals look in compiled code? – user40980 Aug 27 '15 at 19:29
  • 2
    Look at the assembly that the link I provided contains. Its right there. – user40980 Aug 27 '15 at 19:37
  • 8
    Your "moregex" example wouldn't work because of null termination. – dan04 Aug 27 '15 at 19:39
  • 4
    You don't want to write over constants because that will change their value. The next time you want to use the same constant it would be different. The compiler/runtime has to source the constants from somewhere, and wherever that is you shouldn't be allowed to modify. – Erik Eidt Aug 27 '15 at 20:23
  • 1
    'So string literals are stored in program memory, not RAM, and buffer overflow would result in the corruption of program itself?' The program image is in RAM too. To be precise, the string literals are stored in the same segment of RAM used to store the program image. And yes, overwriting the string could corrupt the program. Back in the days of MS-DOS and CP/M there was no memory protection, you could do stuff like this, and it usually caused terrible problems. The first PC viruses would use tricks like that to modify your program so it formatted your hard drive when you tried to run it. – Charles E. Grant Aug 27 '15 at 22:03
up vote 38 down vote accepted

Historically (perhaps by rewriting parts of it), it was the contrary. On the very first computers of the early 1970s (perhaps PDP-11) running a prototypical embryonic C (perhaps BCPL) there was no MMU and no memory protection (which existed on most older IBM/360 mainframes). So every byte of memory (including those handling literal strings or machine code) could be overwritten by an erroneous program (imagine a program changing some % to / in a printf(3) format string). Hence, literal strings and constants were writable.

As a teenager in 1975, I coded in the Palais de la Découverte museum in Paris on old 1960s era computers without memory protection: IBM/1620 had only a core memory -which you could initialize thru the keyboard, so you had to type several dozens of digits to read the initial program on punched tapes; CAB/500 had a magnetic drum memory; you could disable writing some tracks thru mechanical switches near the drum.

Later, computers got some form of memory management unit (MMU) with some memory protection. There was a device forbidding the CPU to overwrite some kind of memory. So some memory segments, notably the code segment (a.k.a. .text segment) became read-only (except by the operating system which loaded them from disk). It was natural for the compiler and the linker to put the literal strings in that code segment, and literal strings became read only. When your program tried to overwrite them, it was bad, an undefined behavior. And having a read-only code segment in virtual memory gives a significant advantage: several processes running the same program share the same RAM (physical memory pages) for that code segment (see MAP_SHARED flag for mmap(2) on Linux).

Today, cheap microcontrollers have some read-only memory (e.g. their Flash or ROM), and keep their code (and the literal strings and other constants) there. And real microprocessors (like the one in your tablet, laptop or desktop) have a sophisticated memory management unit and cache machinery used for virtual memory & paging. So the code segment of the executable program (e.g. in ELF) is memory mapped as a read-only, shareable, and executable segment (by mmap(2) or execve(2) on Linux; BTW you could give directives to ld to get a writable code segment if you really wanted to). Writing or abusing it is generally a segmentation fault.

So the C standard is baroque: legally (only for historical reasons), literal strings are not const char[] arrays, but only char[] arrays that are forbidden to be overwritten.

BTW, few current languages permit string literals to be overwritten (even Ocaml which historically -and badly- had writable literal strings has changed that behavior recently in 4.02, and now has read-only strings).

Current C compilers are able to optimize and have "ions" and "expressions" share their last 5 bytes (including the terminating null byte).

Try to compile your C code in file foo.c with gcc -O -fverbose-asm -S foo.c and look inside the generated assembler file foo.s by GCC

At last, the semantics of C is complex enough (read more about CompCert & Frama-C which are trying to capture it) and adding writable constant literal strings would make it even more arcane while making programs weaker and even less secure (and with less defined behavior), so it is very unlikely that future C standards would accept writable literal strings. Perhaps on the contrary they would make them const char[] arrays as they morally should be.

Notice also that for many reasons, mutable data is harder to handle by the computer (cache coherency), to code for, to understand by the developer, than constant data. So it preferable to have most of your data (and notably literal strings) stay immutable. Read more about functional programming paradigm.

In the old Fortran77 days on IBM/7094, a bug could even change a constant: if you CALL FOO(1) and if FOO happened to modify its argument passed by reference to 2, the implementation might have changed other occurrences of 1 into 2, and that was a really naughty bug, quite hard to find.

  • Is this to protect strings as constants? Even though they are not defined as const in standard (stackoverflow.com/questions/2245664/…)? – Marius Macijauskas Aug 27 '15 at 19:47
  • Are you sure the first computers had no read-only memory? Wasn't that considerably cheaper than ram? Also, putting them into RO-memory doesn't cause cause UB on trying to erroneously modify them, but relying on the OP not doing that and him violating that trust. See for example Fortran-programs where all literal 1s suddenly behave like 2s and such fun... – Deduplicator Aug 27 '15 at 20:23
  • 1
    As a teenager in a museum, I coded in 1975 on old IBM/1620 and CAB500 computers. Neither had any ROM: IBM/1620 had core memory, and CAB500 had a magnetic drum (some tracks could be disabled to be writable by a mechanical switch) – Basile Starynkevitch Aug 27 '15 at 20:25
  • 2
    Also worth pointing out: Putting literals in the code segment means they can be shared among multiple copies of the program because initialization happens at compile time rather than run time. – Blrfl Aug 27 '15 at 20:28
  • @Deduplicator Well, I've seen a machine running a BASIC variant which allowed you to change integer constants (I'm not sure if you needed to trick it into doing so, e.g. passing "byref" arguments or if a simple let 2 = 3 worked). This resulted in a lot of FUN (in the Dwarf Fortress definition of the word), of course. I have no idea how the interpreter was designed that it allowed this, but it was. – Luaan Sep 4 '15 at 12:34

Compilers couldn't combine "more" and "regex", because the former has a null byte after the e while the latter has an x, but many compilers would combine string literals which matched perfectly, and some would also match string literals that shared a common tail. Code which changes a string literal may thus change a different string literal which is used for some entirely different purpose but happens to contain the same characters.

A similar issue would arise in FORTRAN prior to the invention of C. Arguments were always passed by address rather than by value. A routine to add two numbers would thus be equivalent to:

float sum(float *f1, float *f2) { return *f1 + *f2; }

In the event that one wanted to pass a constant value (e.g. 4.0) to sum, the compiler would create an anonymous variable and initialize it to 4.0. If the same value was passed to multiple functions, the compiler would pass the same address to all of them. As a consequence, if a function which modified one of its parameters was passed a floating-point constant, the value of that constant elsewhere in the program could get changed as a result, thus leading to the saying "Variables won't; constants aren't".

Consider a program like grep. Many of the literal constants in it are error messages. By considering them to be immutable and part of the code segment, a multiuser machine can use the same code segment in RAM for dozens of users all running grep simultaneously, even asynchronously.

  • This is true, but was already said in parts of previously given answers (in particular mine). I feel your answer don't add anything new (and is slightly inaccurate: the code segment would be shared by processes, not by users; even a single user could run several grep processes at once) – Basile Starynkevitch Sep 5 '15 at 13:46
  • Stipulated. I think though that pointing out the deficiency of my answer is unnecessary. Just let it not earn votes. OK? – Ross Presser Sep 6 '15 at 23:48

protected by gnat Mar 22 '17 at 4:37

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.