177

I have a class with a private char str[256];

and for it I have an explicit constructor:

explicit myClass(char *func)
{
    strcpy(str,func);
}

I call it as:

myClass obj("example");

When I compile this I get the following warning:

deprecated conversion from string constant to 'char*'

Why is this happening?

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
mkamthan
  • 2,331
  • 3
  • 17
  • 23
  • 3
    You should use `strncpy(str, func, 255)` instead of `strcpy(str, func)` for a safer copy. And then don't forget to add the '\0' at the end of the string since strncpy does not add it. – Patrice Bernassola Oct 06 '09 at 08:55
  • 3
    Safer still to say "strncpy(str, func, sizeof(str)); str[sizeof(str) - 1] = '\0';" – Warren Young Oct 06 '09 at 08:59
  • 3
    I don't think the above gives the warning you quoted, although I'm sure quite similar code would. In order to get meaningful answers, you should post a minimal, compiling example that produces the warning. – sbi Oct 06 '09 at 09:23
  • 3
    @Patrice, Warren: don't use strncpy, it is not a safer version of strcpy. Use (or re-implement) strcpy_s. – Steve Jessop Oct 06 '09 at 15:26
  • I got the problem, its only showing these issues for an -X86 build and not for normal solaris or ARM(target) builds so I am ignoring this. Could not find a fix still as it doesn't shows a warning normally for my sample code as well. Thank you all! – mkamthan Oct 07 '09 at 06:13
  • @mkamthan: That warning is most likely triggered because a string literal is treated as writable memory. This is a very dangerous (and thus deprecated) loophole in the current C++ standard which is only there to allow sloppy old code to keep compiling. You should better get to the bottom of this. Taking a copy of the original code and stripping it down to a small repro case is the best way to find out what causes this. Save that time now, and it's very likely you'll be sorry later. – sbi Oct 07 '09 at 17:10
  • Look at this answer: http://stackoverflow.com/questions/1530469#1530469 – sbi Oct 07 '09 at 17:14
  • @SteveJessop: Did you mean `strcpy_s` as it works when the handler does an `abort`? Because otherwise it's just too bad. – Deduplicator Jan 29 '16 at 15:39
  • @Deduplicator: well, if you're implementing your own version to use in a particular application or library, then you needn't necessarily bother implementing the ability to set the handler. Just have it do whatever you would have wanted it to do. Which should probably end in an abort, but you might be able to do some logging or whatever first. – Steve Jessop Jan 29 '16 at 17:30
  • @SteveJessop: My point is that making the functions behavior dependent on which handler is set is one of the fundamental design-errors of that set of functions. – Deduplicator Jan 29 '16 at 17:35
  • If anyone is here like me to check how to declare a constexpr string literal check this answer: https://stackoverflow.com/a/46100521/3994640 – psykid Oct 30 '20 at 18:31

11 Answers11

178

This is an error message you see whenever you have a situation like the following:

char* pointer_to_nonconst = "string literal";

Why? Well, C and C++ differ in the type of the string literal. In C the type is array of char and in C++ it is constant array of char. In any case, you are not allowed to change the characters of the string literal, so the const in C++ is not really a restriction but more of a type safety thing. A conversion from const char* to char* is generally not possible without an explicit cast for safety reasons. But for backwards compatibility with C the language C++ still allows assigning a string literal to a char* and gives you a warning about this conversion being deprecated.

So, somewhere you are missing one or more consts in your program for const correctness. But the code you showed to us is not the problem as it does not do this kind of deprecated conversion. The warning must have come from some other place.

NelsonGon
  • 13,015
  • 7
  • 27
  • 57
sellibitze
  • 27,611
  • 3
  • 75
  • 95
  • 29
    It is unfortunate considering the view and votes on this question that the OP never provided code that actually demonstrates the problem. – Shafik Yaghmour Mar 11 '15 at 19:23
  • 3
    You can reproduce the issue with the OP's code by deleting the `const` from the `MyClass` constructor...then you can fix it by adding the `const` back. – Theodore Murdock Jan 08 '19 at 18:27
  • I think this is a silly decision. The "string literal" should be changable. I mean what is a string literal? It's a location in memory. If I want to change it, I should be able to as I like. Silly way to break the language. IMHO – baash05 Jul 26 '23 at 00:39
153

The warning:

deprecated conversion from string constant to 'char*'

is given because you are doing somewhere (not in the code you posted) something like:

void foo(char* str);
foo("hello");

The problem is that you are trying to convert a string literal (with type const char[]) to char*.

You can convert a const char[] to const char* because the array decays to the pointer, but what you are doing is making a mutable a constant.

This conversion is probably allowed for C compatibility and just gives you the warning mentioned.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Fernando N.
  • 6,369
  • 4
  • 27
  • 30
112

As answer no. 2 by fnieto - Fernando Nieto clearly and correctly describes that this warning is given because somewhere in your code you are doing (not in the code you posted) something like:

void foo(char* str);
foo("hello");

However, if you want to keep your code warning-free as well then just make respective change in your code:

void foo(char* str);
foo((char *)"hello");

That is, simply cast the string constant to (char *).

Community
  • 1
  • 1
sactiw
  • 21,935
  • 4
  • 41
  • 28
  • 20
    Alternatively, make the function: void foo(const char* str) – Caprooja Apr 14 '14 at 16:28
  • 5
    @Caprooja Yes declaring the param as 'pointer to a constant' will also work in this case. But with this change user can no more change/reassign the value stored at the address using the 'str' pointer which user might be doing in the implementation part. So that is something you might want to look out for. – sactiw Apr 15 '14 at 07:37
  • 1
    @sactiw Are there any reasons to keep `void foo(char* str)` as is? I thought we cannot modity `str` in `foo` anyway, even the parameter is written as non-const. – kgf3JfUtW Nov 22 '16 at 20:21
48

There are 3 solutions:

Solution 1:

const char *x = "foo bar";

Solution 2:

char *x = (char *)"foo bar";

Solution 3:

char* x = (char*) malloc(strlen("foo bar")+1); // +1 for the terminator
strcpy(x,"foo bar");

Arrays also can be used instead of pointers because an array is already a constant pointer.

Update: See the comments for security concerns regarding solution 3.

anilbey
  • 1,817
  • 4
  • 22
  • 38
5

A reason for this problem (which is even harder to detect than the issue with char* str = "some string" - which others have explained) is when you are using constexpr.

constexpr char* str = "some string";

It seems that it would behave similar to const char* str, and so would not cause a warning, as it occurs before char*, but it instead behaves as char* const str.

Details

Constant pointer, and pointer to a constant. The difference between const char* str, and char* const str can be explained as follows.

  1. const char* str : Declare str to be a pointer to a const char. This means that the data to which this pointer is pointing to it constant. The pointer can be modified, but any attempt to modify the data would throw a compilation error.
    1. str++ ; : VALID. We are modifying the pointer, and not the data being pointed to.
    2. *str = 'a'; : INVALID. We are trying to modify the data being pointed to.
  2. char* const str : Declare str to be a const pointer to char. This means that point is now constant, but the data being pointed too is not. The pointer cannot be modified but we can modify the data using the pointer.
    1. str++ ; : INVALID. We are trying to modify the pointer variable, which is a constant.
    2. *str = 'a'; : VALID. We are trying to modify the data being pointed to. In our case this will not cause a compilation error, but will cause a runtime error, as the string will most probably will go into a read only section of the compiled binary. This statement would make sense if we had dynamically allocated memory, eg. char* const str = new char[5];.
  3. const char* const str : Declare str to be a const pointer to a const char. In this case we can neither modify the pointer, nor the data being pointed to.
    1. str++ ; : INVALID. We are trying to modify the pointer variable, which is a constant.
    2. *str = 'a'; : INVALID. We are trying to modify the data pointed by this pointer, which is also constant.

In my case the issue was that I was expecting constexpr char* str to behave as const char* str, and not char* const str, since visually it seems closer to the former.

Also, the warning generated for constexpr char* str = "some string" is slightly different from char* str = "some string".

  1. Compiler warning for constexpr char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *const'
  2. Compiler warning for char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.

Tip

You can use C gibberish ↔ English converter to convert C declarations to easily understandable English statements, and vice versa. This is a C only tool, and thus wont support things (like constexpr) which are exclusive to C++.

Sahil Singh
  • 3,352
  • 39
  • 62
4

In fact a string constant literal is neither a const char * nor a char* but a char[]. Its quite strange but written down in the c++ specifications; If you modify it the behavior is undefined because the compiler may store it in the code segment.

dan ionescu
  • 129
  • 1
  • 8
4

Maybe you can try this:

void foo(const char* str) 
{
    // Do something
}

foo("Hello")

It works for me

Alen Lee
  • 2,479
  • 2
  • 21
  • 30
1

I solve this problem by adding this macro in the beginning of the code, somewhere. Or add it in <iostream>, hehe.

 #define C_TEXT( text ) ((char*)std::string( text ).c_str())
Gigo
  • 3,188
  • 3
  • 29
  • 40
TWOPIR
  • 59
  • 1
  • 9
    _"Or add it in "_ What?! – Lightness Races in Orbit Sep 23 '16 at 15:17
  • There was ", hehe" that was for whatever reason edited out (implied that it was a joke) – Someguynamedpie Oct 23 '16 at 21:56
  • 1
    `C_TEXT` is fine for a function call ( `foo(C_TEXT("foo"));`), but is crying out for undefined behaviour if the value is stored in a variable like `char *x = C_TEXT("foo");` - any use of `x` (apart from assignment) is undefined behaviour because the memory that it is pointing to has been freed. – Martin Bonner supports Monica Jan 30 '18 at 20:22
  • Being fine and compilable doesn't mean it actually works as intended! This creates a pointer to a member of a temporary that has been allocated, then freed and finally used in the function. This is a typical use-after-free bug. – Alexis Paques Jun 04 '21 at 09:55
0

I also got the same problem. And what I simple did is just adding const char* instead of char*. And the problem solved. As others have mentioned above it is a compatible error. C treats strings as char arrays while C++ treat them as const char arrays.

dilantha111
  • 1,388
  • 1
  • 17
  • 19
0

For what its worth, I find this simple wrapper class to be helpful for converting C++ strings to char *:

class StringWrapper {
    std::vector<char> vec;
public:
    StringWrapper(const std::string &str) : vec(str.begin(), str.end()) {
    }

    char *getChars() {
        return &vec[0];
    }
};
bremen_matt
  • 6,902
  • 7
  • 42
  • 90
-1

The following illustrates the solution, assign your string to a variable pointer to a constant array of char (a string is a constant pointer to a constant array of char - plus length info):

#include <iostream>

void Swap(const char * & left, const char * & right) {
    const char *const temp = left;
    left = right;
    right = temp;
}

int main() {
    const char * x = "Hello"; // These works because you are making a variable
    const char * y = "World"; // pointer to a constant string
    std::cout << "x = " << x << ", y = " << y << '\n';
    Swap(x, y);
    std::cout << "x = " << x << ", y = " << y << '\n';
}