3 ms·
The C standard, since 1989, has said that attempting to modify the array object corresponding to a string literal has undefined behavior. Whether it "works" or
by _kst_ 2y ago
The C standard, since 1989, has said that attempting to modify the array object corresponding to a string literal has undefined behavior. Whether it "works" or not is not the issue.
The problem is that it's currently legal to pass a string literal to a function expecting a (non-const) pointer-to-char argument. As long as the function doesn't try to write through the pointer, there's no undefined behavior. (If the function does try to write through the pointer, the behavior is undefined, but no compile-time diagnostic is required.) If a future version of C made string literals const, such a program would become invalid (a constraint violation requiring a diagnostic). Such code was common in pre-ANSI C, before const was introduced to the language.
The following is currently valid C. The corresponding C++ code would be invalid. The proposal would make it invalid in C, with the cost of breaking some existing code, and the advantage of catching certain errors at compile time.
#include <stdio.h>
void print_message(char *message) {
puts(message);
// *message = '\0'; // would have undefined behavior
}
int main(void) {
print_message("hello");
}
- jcalvinowens 2y ago> Whether it "works" or not is not the issue. Of course it is. It doesn't work on anything modern, and thus it is impossible for portable code which actually runs in the real world and has to work to have relied on it for a long time. Your example is not code any competent C programmer would ever write, IMHO. Every proficient C programmer I've ever worked with used "const char *" for string literals, and called out anybody who didn't in review. Old code already needs special flags to build with modern compilers: I think the benefit of doing this outweighs the cost of editing some makefiles.
- ncruces 2y agoThe most current SQLite amalgamation (3.49.1) is showing ~70 warnings when compiled with -Wwrite-strings. But maybe 70 warnings in 250k LoC is OK for your standards of proficiency.
- jcalvinowens 2y agoSurely you agree that is a problem that ought to be fixed in that code? 70 warnings really doesn't sound that bad to fix. Most are probably trivial. I'm sure a few aren't. If nobody is around to fix it, that's what legacy flags are for.
- _kst_ 2y agoA conforming implementation could make string literals modifiable, and (obviously non-portable) code could rely on that. I don't know whether any current compilers do so. I suspect not. Apart from that, it's not about actually modifying string literals. It's about currently valid (but admittedly sloppy) code that uses a non-const pointer to point to a string literal. It's easy to write such code in a way that a modern conforming C compiler will not warn about. That kind of code is the reason that this proposed change is not just an obvious no-brainer, and the author is doing research to find out how much of an issue it really is. As it happens, I think that the next C standard should make string literals const. Any code that depends on the current behavior can still be compiled with C23 or earlier compilers, or with a non-conforming option, or by ignoring non-fatal warnings. And of course any such code can be fixed, but that's not necessarily trivial; making the source code changes can be a very small part of the process. Any change that can break existing valid code should be approached with caution to determine whether it's worth the cost. And if the answer is yes, that's great.
- jcalvinowens 2y ago> That kind of code is the reason that this proposed change is not just an obvious no-brainer I don't understand your point here: I disagree this is "obvious", and I don't think I've said anything to imply that? > And of course any such code can be fixed, but that's not necessarily trivial; making the source code changes can be a very small part of the process In many cases, it's so trivial you can write code to patch the code. Often, the resulting stripped binary will be identical, so you can prove it's not necessary to even test the result! If decision makers can be made to understand that, you can run around most corporate process that makes this sort of thing hard. I've spent a lot of time fixing horrible old proprietary code to use const because I think it's important: most of the time, it's very easy. I don't deny there are rats nests that require a lot of refactoring to unwind, but that is the exception rather than the rule, in my personal experience. It will be vanishingly rare that code will need to be modified in a way that actually changes its runtime behavior to tolerate the proposed change.
- _kst_ 1y agoMy point is that the risk of breaking existing code is the only reason not to apply this change to the standard. My point is also that that's a valid reason to proceed carefully before making the change. Even if the required source code changes are trivial or automatable, there will still be some variable amount of work required to deploy the changes. For a small program or library, maybe you can just rebuild and deploy. But for some projects, any change requires going through a full round of review, testing, recertification, and so on. For an update to code that controls a medical device or a nuclear reactor, for example, changing the code is the easy part. I support the proposed change. I also support performing all due diligence before imposing it on all future implementations and C software.