With this code, I get a segmentation fault:
char* inputStr = "abcde";
*(inputStr+1)='f';
If the code was:
const char* inputStr = "abcde";
*(inputStr+1)='f';
I will get compile error for "assigning read-only location".
However, for the first case, there is no compile error; just the segmentation fault when the assign operation actually happened.
Can anyone explain this?
Here is what the standard says about string literals in section [2.13.4/2]:
A string literal that does not begin with u, U, or L is an ordinary string literal, also referred to as a narrow string literal. An ordinary string literal has type “array of n const char”, where n is the size of the string as defined below; it has static storage duration (3.7) and is initialized with the given characters.
So, strictly speaking, "abcde" has type
const char[6]
Now what happens in your code is an implicit cast to
char*
so that the assignment is allowed. The reason why it is so is, likely, compatibility with C. Have a look also at the discussion here: http://learningcppisfun.blogspot.com/2009/07/string-literals-in-c.html
Once the cast is done, you are syntactically free to modify the literal, but it fails because the compiler stores the literal in a non writable segment of memory, as the standard itself allow.
This gets created in the code segment:
char *a = "abcde";
Essentially it's const.
If you wish to edit it, try:
char a[] = "abcde";
The standard states that you are not allowed to modify string literals directly, regardless of whether you mark them const or not:
Whether all string literals are distinct (that is, are stored in nonoverlapping
objects) is implementation-defined. The effect of attempting to modify a string literal is undefined.
In fact, in C (unlike C++), string literals are not const but you're still not allowed to write to them.
This restriction on writing allows certain optimisations to take place, such as sharing of literals along the lines of:
char *ermsg = "invalid option";
char *okmsg = "valid option";
where okmsg can actually point to the 'v' character in ermsg, rather than being a distinct string.
String literals are typically stored in read-only memory. Trying to change this memory will kill your program.
Here's a good explanation: Is a string literal in c++ created in static memory?
It is mostly ancient history; once upon a long time ago, string literals were not constant.
However, most modern compilers place string literals into read-only memory (typically, the text segment of your program, where your code also lives), and any attempt to change a string literal will yield a core dump or equivalent.
With G++, you can most certainly get the compilation warning (-Wall if it is not enabled by default). For example, G++ 4.6.0 compiled on MacOS X 10.6.7 (but running on 10.7) yields:
$ cat xx.cpp
int main()
{
char* inputStr = "abcde";
*(inputStr+1)='f';
}
$ g++ -c xx.cpp
xx.cpp: In function ‘int main()’:
xx.cpp:3:22: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
$
So the warning is enabled by default.
What happened is that the compiler put the constant "abcde" in some read-only memory segment. You pointed your (non-const) char* inputStr at that constant, and kaboom, segfault.
Lesson to be learned: Don't invoke undefined behavior.
Edit (elaboration)
However, for the first case, there is no compile error, just segmentation fault when the assign operation actually happened.
You need to enabled your compiler warnings. Always set your compiler warnings as high as possible.
Even though "abcde" is a string literal, which should not be modified, you've told the compiler that you don't care about that by having a non-const char* point to it.
The compiler will happily assume that you know what you're doing, and not throw an error. However, there's a good chance that the code will fail at runtime when you do indeed try to modify the string literal.
String literals, while officially non-const, are almost always stored in read-only memory. In your setup, this is apparently only the case if it is declared as const char array.
Note that the standard forbids you to modify any string literal.
a little bit of history of string literals in Ritchie's words.
mostly about the orgin and the evolution of string literals from K&R 1.
Hope this might clarify a thing or two about const and string literals.
"From: Dennis Ritchie
Subject: Re: History question: String literals.
Date: 02 Jun 1998
Newsgroups: comp.std.c
At the time that the C89 committee was working, writable
string literals weren't "legacy code" (Margolin) and what standard
there existed (K&R 1) was quite explicit (A.2.5) that
strings were just a way of initializing a static array.
And as Barry pointed out there were some (mktemp) routines
that used this fact.
I wasn't around for the committee's deliberations on the
point, but I suspect that the BSD utility for fiddling
the assembler code to move the initialization of strings
to text instead of data, and the realization that most
literal strings were not in fact overwritten, was more
important than some very early version of gcc.
Where I think the committee might have missed something
is in failure to find a formulation that explained
the behavior of string literals in terms of const.
That is, if "abc" is an anonymous literal of type
const char [4]
then just about all of its properties (including the
ability to make read-only, and even to share its storage
with other occurrences of the same literal) are nearly
explained.
The problem with this was not only the relatively few
places that string literals were actually written on, but much
more important, working out feasible rules for assignments
to pointers-to-const, in particular for function's actual
arguments. Realistically the committee knew that whatever
rules they formulated could not require a mandatory
diagnostic for every func("string") in the existing world.
So they decided to leave "..." of ordinary char array
type, but say one was required not to write over it.
This note, BTW, isn't intended to be read as a snipe
at the formulation in C89. It is very hard to get things
both right (coherent and correct) and usable (consistent
enough, attractive enough).
Dennis
"
Related
In the past i've been using Visual Studio 2010/2013/2015 and this syntax was possible :
char* szString = "This works!";
I've decided to step on and change my lifestyle of coding towards Linux, as I have installed g++ and have SlickEdit as my IDE.
It seems like that sentence doesn't work anymore.
Can anyone please state why?
This works however :
char strString[] = "This works!";
The error is something with c++11.
Does anyone have an idea why this happens? Not how to fix it, cause in my workspace there isn't any way to install a c++11 compiler, i'm just curious if it has to do with something on the background on how the compiler works.
What I do know about the first line of code, is that it creates a constant variable on the stack and creates a new pointer setting itself towards that ESP's value, but on the second one it counts the amount of letters on the constant variable and then sets a null terminator in the end as a result.
Oh and one more thing -> There seems to be a difference also in the way the first one is set in GCC/GPP, as the first type is {char*&} and the second one is {char(*)[12]}, any explanation on that too? Thanks!
When you write the literal "text", that text will be included somewhere the compiled program image. The program image is usually placed in write-protected memory on modern operating systems for security reasons.
char* someString = "text"; declares a pointer to the string in your probably-write-protected program image. The ability to declare this pointer as non-const was a feature included until C++11 to maintain source compatibility with C. Note that even though someString is not a pointer-to-const, any attempt to modify the value that it points to will still result in undefined behavior. This backwards compatibility feature was removed in C++11. someString must now be declared as pointer-to-const: const char* someString = "text";. You can cast the const away, but attempting to write to the value pointed to will still result in undefined behavior the same as any const value you cast to non-const.
char someString[] = "text"; works differently. This copies the string "text" from your program's code memory into an array located in data memory. It's similar to
char someString[5];
strcpy(someString, "text");
Since someString is an array in your program's data memory, it's fine to write to it, and it doesn't need to be const-qualified.
According to the standard: Annex C (Compatability)
C1.1 Subclause 2.14.5:
Change: String literals made const
The type of a string literal is changed from “array of char” to “array of const char.” The type of a char16_t string literal is changed from “array of some-integer-type” to “array of const char16_t.” The type of a char32_t string literal is changed from “array of some-integer-type” to “array of const char32_t.”
The type of a wide string literal is changed from “array of wchar_t” to “array of const wchar_t.”
Rationale: This avoids calling an inappropriate overloaded function, which might expect to be able to modify its argument.
And indeed, the C++ standard 2.14.5.8 says:
Ordinary string literals and UTF-8 string literals are also referred to as narrow string literals. A narrow string literal has type “array of n const char”, where n is the size of the string as defined below, and has static storage duration
This is also allows such strings get various special treatment: the compiler/linker can choose to eliminate duplicates of a string across compilation units, (string pooling in msvc terms), it can store them in the data section and read only memory.
2.14.5.12
Whether all string literals are distinct (that is, are stored in nonoverlapping objects) is implementationdefined. The effect of attempting to modify a string literal is undefined.
The char* x = "hello world"; is a throw-back to C++'s inheritance from early C. Visual Studio supports it because of the heavy baggage in their own libraries.
I'm currently learning pointers and my professor provided this piece of code as an example:
//We cannot predict the behavior of this program!
#include <iostream>
using namespace std;
int main()
{
char * s = "My String";
char s2[] = {'a', 'b', 'c', '\0'};
cout << s2 << endl;
return 0;
}
He wrote in the comments that we can't predict the behavior of the program. What exactly makes it unpredictable though? I see nothing wrong with it.
The behaviour of the program is non-existent, because it is ill-formed.
char* s = "My String";
This is illegal. Prior to 2011, it had been deprecated for 12 years.
The correct line is:
const char* s = "My String";
Other than that, the program is fine. Your professor should drink less whiskey!
The answer is: it depends on what C++ standard you're compiling against. All the code is perfectly well-formed across all standards‡ with the exception of this line:
char * s = "My String";
Now, the string literal has type const char[10] and we're trying to initialize a non-const pointer to it. For all other types other than the char family of string literals, such an initialization was always illegal. For example:
const int arr[] = {1};
int *p = arr; // nope!
However, in pre-C++11, for string literals, there was an exception in §4.2/2:
A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; [...]. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See Annex D. ]
So in C++03, the code is perfectly fine (though deprecated), and has clear, predictable behavior.
In C++11, that block does not exist - there is no such exception for string literals converted to char*, and so the code is just as ill-formed as the int* example I just provided. The compiler is obligated to issue a diagnostic, and ideally in cases such as this that are clear violations of the C++ type system, we would expect a good compiler to not just be conforming in this regard (e.g. by issuing a warning) but to fail outright.
The code should ideally not compile - but does on both gcc and clang (I assume because there's probably lots of code out there that would be broken with little gain, despite this type system hole being deprecated for over a decade). The code is ill-formed, and thus it does not make sense to reason about what the behavior of the code might be. But considering this specific case and the history of it being previously allowed, I do not believe it to be an unreasonable stretch to interpret the resulting code as if it were an implicit const_cast, something like:
const int arr[] = {1};
int *p = const_cast<int*>(arr); // OK, technically
With that, the rest of the program is perfectly fine, as you never actually touch s again. Reading a created-const object via a non-const pointer is perfectly OK. Writing a created-const object via such a pointer is undefined behavior:
std::cout << *p; // fine, prints 1
*p = 5; // will compile, but undefined behavior, which
// certainly qualifies as "unpredictable"
As there is no modification via s anywhere in your code, the program is fine in C++03, should fail to compile in C++11 but does anyway - and given that the compilers allow it, there's still no undefined behavior in it†. With allowances that the compilers are still [incorrectly] interpreting the C++03 rules, I see nothing that would lead to "unpredictable" behavior. Write to s though, and all bets are off. In both C++03 and C++11.
†Though, again, by definition ill-formed code yields no expectation of reasonable behavior
‡Except not, see Matt McNabb's answer
Other answers have covered that this program is ill-formed in C++11 due to the assignment of a const char array to a char *.
However the program was ill-formed prior to C++11 also.
The operator<< overloads are in <ostream>. The requirement for iostream to include ostream was added in C++11.
Historically, most implementations had iostream include ostream anyway, perhaps for ease of implementation or perhaps in order to provide a better QoI.
But it would be conforming for iostream to only define the ostream class without defining the operator<< overloads.
The only slightly wrong thing that I see with this program is that you're not supposed to assign a string literal to a mutable char pointer, though this is often accepted as a compiler extension.
Otherwise, this program appears well-defined to me:
The rules that dictate how character arrays become character pointers when passed as parameters (such as with cout << s2) are well-defined.
The array is null-terminated, which is a condition for operator<< with a char* (or a const char*).
#include <iostream> includes <ostream>, which in turn defines operator<<(ostream&, const char*), so everything appears to be in place.
You can't predict the behaviour of the compiler, for reasons noted above. (It should fail to compile, but may not.)
If compilation succeeds, then the behaviour is well-defined. You certainly can predict the behaviour of the program.
If it fails to compile, there is no program. In a compiled language, the program is the executable, not the source code. If you don't have an executable, you don't have a program, and you can't talk about behaviour of something that doesn't exist.
So I'd say your prof's statement is wrong. You can't predict the behaviour of the compiler when faced with this code, but that's distinct from the behaviour of the program. So if he's going to pick nits, he'd better make sure he's right. Or, of course, you might have misquoted him and the mistake is in your translation of what he said.
As others have noted, the code is illegitimate under C++11, although it was valid under earlier versions. Consequently, a compiler for C++11 is required to issue at least one diagnostic, but behavior of the compiler or the remainder of the build system is unspecified beyond that. Nothing in the Standard would forbid a compiler from exiting abruptly in response to an error, leaving a partially-written object file which a linker might think was valid, yielding a broken executable.
Although a good compiler should always ensure before it exits that any object file it is expected to have produced will be either valid, non-existent, or recognizable as invalid, such issues fall outside the jurisdiction of the Standard. While there have historically been (and may still be) some platforms where a failed compilation can result in legitimate-appearing executable files that crash in arbitrary fashion when loaded (and I've had to work with systems where link errors often had such behavior), I would not say that the consequences of syntax errors are generally unpredictable. On a good system, an attempted build will generally either produce an executable with a compiler's best effort at code generation, or won't produce an executable at all. Some systems will leave behind the old executable after a failed build, since in some cases being able to run the last successful build may be useful, but that can also lead to confusion.
My personal preference would be for disk-based systems to to rename the output file, to allow for the rare occasions when that executable would be useful while avoiding the confusion that can result from mistakenly believing one is running new code, and for embedded-programming systems to allow a programmer to specify for each project a program that should be loaded if a valid executable is not available under the normal name [ideally something which which safely indicates the lack of a useable program]. An embedded-systems tool-set would generally have no way of knowing what such a program should do, but in many cases someone writing "real" code for a system will have access to some hardware-test code that could easily be adapted to the purpose. I don't know that I've seen the renaming behavior, however, and I know that I haven't seen the indicated programming behavior.
A quick question: why doesn't C++11 offer a "user-" (really, standard library) defined literal for creating a std::string, such as
auto str = "hello world"s; // str is a std::string
Like C++, Objective-C supports both C-style strings and a more user-friendly library type NSString; however, unlike C++, nobody ever gets confused between the two, because it's trivial to create an NSString by prefixing a string literal with #. In fact, it's rare to see Objective-C code where a literal doesn't have the # prefix. Everybody just knows that's the way to do it, uses NSString and gets on with it.
C++11 user-defined literals would allow this, and in fact the UDL section on Stroustrup's C++11 FAQ uses exactly this example. Furthermore, UDLs without a leading underscore are reserved, so there would be no problem in allowing a plain s as above -- there's no possibility of it clashing with anything else.
Perhaps I'm missing something, but it seems like this would be a very valuable and risk-free addition to the language, so does anybody know why C++11 doesn't offer it? Is it likely to appear in C++14?
User-defined literals were new enough in C++11 that this wasn't included, but it is in C++14( in §21.7, in case anybody cares). And yes, it uses s as the suffix. The precise result type depends on the type of the string literal itself -- a "narrow" literal gives an std::string, a u16 literal gives a u16string, and a u32 literal gives a u32string. Oh, and yeah, if you insist on using a wide string literal it'll produce a wstring.
Note that the s suffix is also used to mean seconds (defined in <chrono>) but there's no real conflict between the two--s on a string literal means a string, and s on a number means seconds.
I am confused why compiler gives
const char s[]="hello";
s[2]='t'; // Compile Time Error
char *t = "hello";
*(t+2)='u'; // Run time Error
I guess in both case the compiler should give compile time error. Can anyone tell me particular reason for this to be this way?
In the first case, you are writing to a const and the compiler notices that and can reject that.
In the second case, t is a pointer to a non-const char, so you can dereference it and write at *(t+2). However, since t is initialized with a pointer to a read-only segment, you are getting a segmentation violation at runtime.
You could painfully configure your linker to put all data in writable segments. This is ugly and non standard.
P.S. Some sophisticated static analyzers (maybe Frama-C) might catch both errors without running the program. One could also imagine extending GCC e.g. with MELT to add such checks (but this is non-trivial work, and it might be hard to get funded for it).
Backwards compatibility.
You can't modify a const char. That much is obvious.
What isn't obvious is that the type of a string literal is actually a pointer to constant characters, not a pointer to characters. The second declaration, actually, therefore has a wrong type. This is supported, however, for historical reasons.
Note that the above is a bit of a lie. Rather than pointers, string literals are actually char[] types.
In particular, the type of a string literal is a char[] rather than a const char[] in C89 and C99 [and I think C11, not sure though]. It's not actually wrong then, but the data is stored in a read only segment, so it's undefined behavior to try to write to it.
Also, for what it's worth, you can use -Wwrite-strings with gcc (g++ already includes it) to be warned of this.
More information here and here.
When you do: char *t = "hello"; then t is a pointer that points to a memory that is in the code part, so you can't change it. Because it's read-only, you're getting segmentation fault at runtime.
When you do: const char s[]="hello"; then s is an array of chars that are on the stack, but it's const, so you can't change it and you get a compilation error (The compiler knows it is const so he doesn't allow you to change it).
Using const when you don't want your String to be changed is good because this arise a compilation error, which is a way better than a run time error.
Consider the following series of statements:
char *t = "hello";
char s[5];
t = s;
*(t+2)='u';
This series of statements will give no run time error, because the statement *(t+2)='u'; is not invalid. It is trying to modify a const (read-only) memory location in your case, but the compiler has no way of knowing whether an access violation will occur.
It is known that in C++ string literals are immutable and the result of modifying a string literal is undefined. For example
char * str = "Hello!";
str[1] = 'a';
This will bring to an undefined behavior.
Besides that string literals are placed in static memory. So they exists during whole program. I would like to know why do string literals have such properties.
There are a couple of different reasons.
One is to allow storing string literals in read-only memory (as others have already mentioned).
Another is to allow merging of string literals. If one program uses the same string literal in several different places, it's nice to allow (but not necessarily require) the compiler to merge them, so you get multiple pointers to the same memory, instead of each occupying a separate chunk of memory. This can also apply when two string literals aren't necessarily identical, but do have the same ending:
char *foo = "long string";
char *bar = "string";
In a case like this, it's possible for bar to be foo+5 (if I'd counted correctly).
In either of these cases, if you allow modifying a string literal, it could modify the other string literal that happens to have the same contents. At the same time, there's honestly not a lot of point in mandating that either -- it's pretty uncommon to have enough string literals that you could overlap that most people probably want the compiler to run slower just to save (maybe) a few dozen bytes or so of memory.
By the time the first standard was written, there were already compilers that used all three of these techniques (and probably a few others besides). Since there was no way to describe one behavior you'd get from modifying a string literal, and nobody apparently thought it was an important capability to support, they did the obvious: said even attempting to do so led to undefined behavior.
It's undefined behaviour to modify a literal because the standard says so. And the standard says so to allow compilers to put literals in read only memory. And it does this for a number of reasons. One of which is to allow compilers to make the optimisation of storing only one instance of a literal that is repeated many times in the source.
I believe you ask about the reason why literals are placed in
read-only memory, not about technical details of linker doing this and
that or legal details of a standard forbidding such and such.
When modification of string literals works, it leads to subtle bugs
even in the absence of string merging (which we have reasons to
disallow if we decided to permit modification). When you see code like
char *str="Hello";
.../* some code, but str and str[...] are not modified */
printf("%s world\n", str);
it's a natural conclusion that you know what's going to be printed,
because str (and its content) were not modified in a particular
place, between initialization and use.
However, if string literals are writable, you don't know it any
more: str[0] could be overwritten later, in this code or inside a
deeply nested function call, and when the code is run again,
char *str="Hello";
won't guarantee anything about the content of str anymore. As we
expect, this initialization is implemented as moving the address known
in link time into a place for str. It does not check that str
contains "Hello" and it does not allocate a new copy of it. However,
we understand this code as resetting str to "Hello". It's hard to
overcome this natural understanding, and it's hard to reason about the
code where it is not guaranteed. When you see an expression like
x+14, what if you had to think about 14 being possibly overwritten
in other code, so it became 42? The same problem with strings.
That's the reason to disallow modification of string literals, both in
the standard (with no requirement to detect the failure early) and in
actual target platforms (providing the bonus of detecting potential
bugs).
I believe that many attempts to explain this thing suffer from the
worst kind of circular reasoning. The standard forbids writing to
literals because the compiler can merge strings, or they can be placed
in read-only memory. They are placed in read-only memory to catch the
violation of the standard. And it's valid to merge literals because
the standard forbids... is it a kind of explanation you asked for?
Let's look at other
languages. Common Lisp standard
makes modification of literals undefined behaviour, even though the
history of preceding Lisps is very different with the history of C
implementations. That's because writable literals are logically
dangerous. Language standards and memory layouts only reflect that
fact.
Python language has exactly one place where something resembling
"writing to literals" can happen: parameter default values, and this
fact confuses people all the time.
Your question is tagged C++, and I'm unsure of its current state
with respect to implicit conversion to non-const char*: if it's a
conversion, is it deprecated? I expect other answers to provide a
complete enlightenment on this point. As we talk of other languages
here, let me mention plain C. Here, string literals are not const,
and an equivalent question to ask would be why can't I modify string
literals (and people with more experience ask instead, why are
string literals non-const if I can't modify them?). However, the
reasoning above is fully applicable to C, despite this difference.
Because is K&R C, there was not such thing as "const". And similarly in pre-ANSI C++. Hence there was a lot of code which had things like char * str = "Hello!"; If the Standards committee made text literals const, all those programs would have no longer compiled. So they made a compromise. Text literals are official const char[], but they have a silent implicit conversion to char*.
In C++, string literals are const because you aren't allowed
to modify them. In standard C, they would have been const as
well, except that when const was introduced into C, there was
so much code along the lines of char* p = "somethin"; that
making them const would have broke, that it was deemed
unacceptable. (The C++ committee chose a different solution to
this problem, with a deprecated implicit conversion which allows
the above.)
In the original C, string literals were not const, and were
mutable, and it was garanteed that no two string literals shared
any memory. This was quickly realized to be a serious error,
allowing things like:
void
mutate(char* p)
{
static char c = 'a';
*p = a ++;
}
and in another module:
mutate( "hello" ); // Can't trust what is written, can you.
(Some early implementations of Fortran had a similar issue,
where F(4) might call F with just about any integral value.
The Fortran committee fixed this, just like the C committee
fixed string literals in C.)