266

The C++11 Standard (ISO/IEC 14882:2011) says in § C.1.1:

char* p = "abc"; // valid in C, invalid in C++

For the C++ it's OK as a pointer to a String Literal is harmful since any attempt to modify it leads to a crash. But why is it valid in C?

The C++11 says also:

char* p = (char*)"abc"; // OK: cast added

Which means that if a cast is added to the first statement it becomes valid.

Why does the casting makes the second statement valid in C++ and how is it different from the first one? Isn't it still harmful? If it's the case, why did the standard said that it's OK?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
rullof
  • 7,124
  • 6
  • 27
  • 36
  • 6
    C++11 doesn't allow the first one. I have no idea why C made the type of a string literal `char[]` in the first place. The second one is a `const_cast` in disguise. – chris Jan 06 '14 at 07:08
  • 4
    There is simply too much legacy C code that would break if this rule were changed. – Paul R Jan 06 '14 at 07:08
  • 1
    please quote the text where the Standard says the second is `OK`. – Nawaz Jan 06 '14 at 07:12
  • Ah, discovering context, this discusses the change of the string literal's type. The entire point of that cast is the path of least resistance to backward-compatibility. – chris Jan 06 '14 at 07:14
  • 23
    The C language had string literals before it had `const`, so they were necessarily not `const`. – Casey Jan 06 '14 at 07:46
  • 7
    C and C++ allows you to cast from nearly any type to another type. That does not mean these casts are meaningful and safe. – Siyuan Ren Jan 06 '14 at 08:02
  • 4
    More importantly, this question must be born from some idea that the two languages have more in common than they do. This is proven incorrect by the error message, so why do you think it's a good idea to ask about the two languages as though you expect them to have a common subset? Programming in that common subset is a waste of your time; you'll be relying upon the worst of both worlds. Choose one or the other, and use the linker when you need to link modules from different languages. – autistic Jul 12 '17 at 04:16
  • "Which means that if a cast is added to the first statement it becomes valid" - No. It just means that it'll compile since you effectively told the compiler "shut up, I know what I'm doing". But it's still not valid to try to modify the string literal through the `char*`. Just beacause something *compiles* does not mean that it is *valid* C++. – Jesper Juhl Aug 01 '23 at 16:33

4 Answers4

323

Up through C++03, your first example was valid, but used a deprecated implicit conversion--a string literal should be treated as being of type char const *, since you can't modify its contents (without causing undefined behavior).

As of C++11, the implicit conversion that had been deprecated was officially removed, so code that depends on it (like your first example) should no longer compile.

You've noted one way to allow the code to compile: although the implicit conversion has been removed, an explicit conversion still works, so you can add a cast. I would not, however, consider this "fixing" the code.

Truly fixing the code requires changing the type of the pointer to the correct type:

char const *p = "abc"; // valid and safe in either C or C++.

As to why it was allowed in C++ (and still is in C): simply because there's a lot of existing code that depends on that implicit conversion, and breaking that code (at least without some official warning) apparently seemed to the standard committees like a bad idea.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • So the second one just gives more flexibility but it's more dangerous? – rullof Jan 06 '14 at 07:21
  • 9
    @rullof: It's dangerous enough that it doesn't give any meaningful flexibility, at least for code that cares (at all) about portability. Writing to a string literal will typically get your program aborted on a modern OS, so allowing code to (try to) write there doesn't add any meaningful flexibility. – Jerry Coffin Jan 06 '14 at 07:30
  • 4
    The code snippet given in this answer `char const *p = "abc";` is "valid and safe in **both** C **and** C++", not "valid and safe in **either** C **or** C++". – Daniel Le Dec 30 '16 at 14:46
  • 7
    @DanielLe both of those sentences have the same meaning – Caleth May 04 '18 at 14:50
  • @DanielLe, (true AND true) === true, (true OR true) === true. :l – secavfr Aug 06 '18 at 16:47
  • @FlavienB. I was referring to “either or” in the sense of picking *a* choice between two choices (https://www.google.com/amp/s/dictionary.cambridge.org/amp/british-grammar/either-or). – Daniel Le Aug 07 '18 at 03:12
  • 8
    Oh my lord! [Insert tongue firmly in cheek] Sorry, but "or" is the correct term here. The code can be compiled as either C or as C++, but cannot be simultaneously compiled as both C and C++. You can choose either, but you must make a choice. You can't have both at once. [resume normal tongue operation]. – Jerry Coffin Aug 07 '18 at 03:57
  • 5
    No, *both/and* is the clearest and most correct wording here. *Either/or* also happens to convey the right meaning, but it's not as clear technically. *Or* alone is irrefutably wrong (*A or B* is not equal to *A and B*). – Apollys supports Monica Sep 14 '18 at 18:13
  • According to this post: https://stackoverflow.com/questions/890535/what-is-the-difference-between-char-const-and-const-char, would it be better to use `const char *p = "abc"` – an offer can't refuse Sep 25 '18 at 15:00
  • 2
    @buzhidao: To the compiler, `char const *` and `const char *` are the same. The one that's different is `char *const` (which won't work, for the same reason unadorned `char *` won't work). – Jerry Coffin Sep 25 '18 at 15:59
29

It's valid in C for historical reasons. C traditionally specified that the type of a string literal was char * rather than const char *, although it qualified it by saying that you're not actually allowed to modify it.

When you use a cast, you're essentially telling the compiler that you know better than the default type matching rules, and it makes the assignment OK.

Barmar
  • 741,623
  • 53
  • 500
  • 612
13

You can also use strdup:

char* p = strdup("abc");

or

char p[] = "abc";

as pointed here

baz
  • 1,317
  • 15
  • 10
  • 5
    Note that `"abc"` got duplicated and pointer `p` should be `free`d to avoid memory leak. – cartoonist Oct 13 '20 at 09:59
  • I originally wanted to do a simple cast `char* p = (char*)"abcXXXXX";` but my program crashed, because I am actually modifying the string later (I am using `mkstemp` to replace the X's). This solution worked. And I did not forget to `free(p)`. – user7610 Oct 15 '20 at 13:56
  • 1
    I'm sure the asker knows this; the question is *why* C and C++ have different rules here. – Toby Speight Dec 30 '20 at 09:37
  • Note that strdup is POSIX standard: https://pubs.opengroup.org/onlinepubs/009604599/functions/strdup.html However this hurt perf. Also need to take care to free the duplicated `char*` otherwise mem leak – KFL Nov 20 '22 at 21:23
6

You can declare like one of the below options:

char data[] = "Testing String";

or

const char* data = "Testing String";

or

char* data = (char*) "Testing String";
Shiv Buyya
  • 3,770
  • 2
  • 30
  • 25