427

I'm working on an exceedingly large codebase, and recently upgraded to GCC 4.3, which now triggers this warning:

warning: deprecated conversion from string constant to ‘char*’

Obviously, the correct way to fix this is to find every declaration like

char *s = "constant string";

or function call like:

void foo(char *s);
foo("constant string");

and make them const char pointers. However, that would mean touching 564 files, minimum, which is not a task I wish to perform at this point in time. The problem right now is that I'm running with -Werror, so I need some way to stifle these warnings. How can I do that?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Josh Matthews
  • 12,816
  • 7
  • 36
  • 39
  • 2
    When you do come to tackle replacing 554 lines, sed is a good friend. Make sure you back up first though. – hookenz Sep 30 '15 at 00:21
  • 2
    I looked at the discussions about how to suppress the error messages and what the correct replacements should be. I don't have any opinions about that. However, I think that Matt is on the right track. Define what you want to replace by what. You just need the right regular expression(s). Make the changes in a copy. Use "diff" to compare them with the original. Making the changes using sed is quick, easy and free, and diff is also quick, easy and free. Try it and see how many changes you have to review. Post what you want to replace by what, and let users suggest regex replacements. – Thomas Hedden Jan 23 '17 at 02:27
  • The entire discussion is missing the point of *why* this is a problem that needs fixing at all according to the gcc warning. The reason is in David Schwartz' answer https://stackoverflow.com/questions/56522654/why-the-warining-deprecated-conversion-from-string-constant-to-char-occured-i. – andig May 26 '20 at 14:59
  • 564 files is entirely doable. Just do it. (Well, in all likelihood you have done it by now ;-) ). – Peter - Reinstate Monica Jun 10 '21 at 11:40

23 Answers23

583

Any functions into which you pass string literals "I am a string literal" should use char const * as the type instead of char*.

If you're going to fix something, fix it right.

Explanation:

You can not use string literals to initialise strings that will be modified, because they are of type const char*. Casting away the constness to later modify them is undefined behaviour, so you have to copy your const char* strings char by char into dynamically allocated char* strings in order to modify them.

Example:

#include <iostream>

void print(char* ch);

void print(const char* ch) {
    std::cout<<ch;
}

int main() {
    print("Hello");
    return 0;
}
phoenix
  • 7,988
  • 6
  • 39
  • 45
John
  • 7,301
  • 2
  • 16
  • 23
  • 27
    While this is true, you don't always have control over 3rd party API's which might not correctly use `char *` / `const char *`, so in that case I normally cast. – ideasman42 Apr 02 '14 at 04:15
  • 17
    @ppumkin Unfortunately, many C standard library string functions take arguments as `char*` even for strings that will not be modified. If you take a parameter as a `char const*` and pass it to a standard function taking a `char*` you'll hit that. If the library function will not be manipulating the string, you may cast away the `const`. – John Jun 08 '15 at 03:10
  • Just because it isn't always possible doesn't mean it isn't the preferred option for many of the times this warning appears in common production code. – LovesTha May 23 '17 at 23:31
  • Even if I smell this is the correct answer, I believe it lacks a proper explanation. Would you please edit and add an explanation? It doesn't need to be detailed. Maybe a few words and a link? – NicoBerrogorry Dec 06 '17 at 18:17
  • 1
    I now fully understand the solution, and the functionality of string literals. But maybe others do not, so I 'hold' the need for an explanation – NicoBerrogorry Dec 06 '17 at 18:28
  • 1
    I don't understand how to apply your solution :( – desmond13 Mar 08 '18 at 15:53
  • this should be accepted answer as it states to use **const** char* instead of char* for constant strings. – Haseeb Mir May 25 '18 at 18:03
240

I believe passing -Wno-write-strings to GCC will suppress this warning.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DGentry
  • 16,111
  • 8
  • 50
  • 66
  • 6
    Is it can be disabled on per file basic using pragmas. – Priyank Bolia Jun 21 '09 at 15:50
  • 21
    @PriyankBolia bdonlan commented on Rob Walker's answer that it can using `#pragma GCC diagnostic ignored "-Wwrite-strings"`. – MasterMastic Jan 18 '13 at 21:05
  • 9
    Except if you control the API, in which case @John's answer below, about changing the signature to accept const char*, is more correct. – jcwenger Jun 27 '14 at 15:07
  • 229
    THIS IS HORRIBLY BAD PRACTICE, and I'm sad it got all those votes. Warnings are not there so that you ignore them. Warnings are there telling you "dude, you're doing something that could be wrong, be careful", and you should only suppress them when you wanna respond like "shut up, I know what I'm doing", which is most likely not the case with infant programmers. – The Quantum Physicist Apr 07 '15 at 09:43
  • 11
    I agree, you shouldn't get rid of the warning and instead use the solution provided by John. Too bad this one is the accepted answer ! – Jérôme Aug 31 '15 at 13:42
  • this obviously needs to be done at the Compile phase, and not at the final Link phase. – DragonLord Dec 05 '15 at 03:12
  • 1
    If you want to keep the warnings but stop them being treated as errors you can do "-Wno-error=write-strings". – plugwash Aug 19 '16 at 11:25
  • 1
    Why isn't "Don't pass -werror" an even better answer? That solves not just this problem but the next one too. – David Schwartz Jan 30 '17 at 18:28
  • 2
    The problem with warnings is that it's all too easy for the really important warnings to get lost in a sea of minor warnings, build progress reports and so-on. Whereas errors get immediate attention because they cause the build to fail. IMO during development it's better to make individual warnings nonfatal using "-Wno-error=" than to get rid of Werror complerely. – plugwash May 19 '17 at 15:49
  • 1
    It is really disappointing that the accepted answer does not ADDRESS the problem, but merely MASKS it :( – Andrew Aug 08 '22 at 08:54
75

I had a similar problem, and I solved it like this:

#include <string.h>

extern void foo(char* m);
 
int main() {
    // warning: deprecated conversion from string constant to ‘char*’
    //foo("Hello");
   
    // no more warning
    char msg[] = "Hello";
    foo(msg);
}

I did not have access to foo in order to adapt it to accept const char*, which would be a better solution because foo did not change m.

BlackShift
  • 2,296
  • 2
  • 19
  • 27
  • 8
    @elcuco , what would you propose? I couldn't edit foo, and tried to find a solution that did not require suppression of the warning. In my case the latter was more a matter of exercise, but for the original poster it seemed important. As far as I can tell, my answer is the only one that would solve both my and the OP's conditions at the same time so it could be a valuable answer to someone. If you think my solution is not good enough, could you please provide an alternative? (That does not include editing foo or ignoring the warning.) – BlackShift Sep 28 '09 at 16:45
  • if we assume that foo is properly codded (which unfortunately does not seem to be the case for the code 'Josh Matthews' is talking about) this is the best solution. that's because if the function needs to actually change the string 'msg' passing it a constant string would break the code, right? but anyway this does not seem to answer the question because the errors are already in the old code not in the new, so he would need to change the old code anyway. – João Portela Nov 03 '09 at 19:43
  • That is the approach I took too. And if somebody is searching this for the cases of `char **` in `PyArg_ParseTupleAndKeywords` I do something like this: `static char kw[][16] = {"mode", "name", "ip", "port"}; static char * kwlist[] = {kw[0], kw[1], kw[2], kw[3], NULL};` – dashesy May 16 '12 at 04:56
  • @elcuco: I'm not sure how C++ static arrays work. Will this really copy any data, and not just pointer ? – Alexander Malakhov Feb 11 '13 at 09:41
  • 2
    While this approach may have merit in some cases applying it blindly is IMO likely to do more harm than good. Applying this blindly could easilly lead to dangling pointers. It will also bloat the code with pointless string copies. – plugwash May 19 '17 at 15:30
  • In tight loops with simple functions operating on the string the performance penalty may be unacceptable. – Peter - Reinstate Monica Jun 10 '21 at 11:39
68

Check out GCC's Diagnostic Pragma support, and the list of -W warning options.

For GCC, you can use #pragma warning directives like explained here.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rob Walker
  • 46,588
  • 15
  • 99
  • 136
34

If it's an active code base, you might still want to upgrade the code base. Of course, performing the changes manually isn't feasible but I believe that this problem could be solved once and for all by one single sed command. I haven't tried it, though, so take the following with a grain of salt.

find . -exec sed -E -i .backup -n \
    -e 's/char\s*\*\s*(\w+)\s*= "/char const* \1 = "/g' {} \;

This might not find all places (even not considering function calls) but it would alleviate the problem and make it possible to perform the few remaining changes manually.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
28

Here is how to do it inline in a file, so you don't have to modify your Makefile.

// gets rid of annoying "deprecated conversion from string constant blah blah" warning
#pragma GCC diagnostic ignored "-Wwrite-strings"

You can then later...

#pragma GCC diagnostic pop
EdH
  • 3,194
  • 3
  • 21
  • 23
26

Replace

char *str = "hello";

with

char *str = (char*)"hello";

or if you are calling in function:

foo("hello");

replace this with

foo((char*) "hello");
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
takataka
  • 285
  • 3
  • 2
25

I can't use the compiler switch. So I have turned this:

char *setf = tigetstr("setf");

to this:

char *setf = tigetstr((char *)"setf");
vy32
  • 28,461
  • 37
  • 122
  • 246
  • 1
    +1 - you cannot change lvalue of applications, only rvalue. this proved to fix the real problem. other just work around some issues with the compiler. – elcuco Sep 22 '09 at 14:50
  • 2
    The thing that is really annoying is that tigetstr() should be prototyped with a (const char *), not a (char *) – vy32 Sep 23 '09 at 06:24
  • 3
    When I do this I get "warning : cast from type 'const char*' to type 'char*' casts away constness" instead. I had to use a const_cast to get rid of all warnings: const_cast("setf") – CrouZ Mar 05 '15 at 09:58
  • 2
    I think the const cast is the first acceptable solution on this page (except the API change). – rwst Apr 14 '15 at 15:45
15

Instead of:

void foo(char *s);
foo("constant string");

This works:

void foo(const char s[]);
foo("constant string");
gipinani
  • 14,038
  • 12
  • 56
  • 85
John
  • 151
  • 1
  • 2
  • This is the correct way to do it since you shouldn't pass a (constant) string to a function that expects a non-constant string anyway! – jfla Dec 12 '14 at 17:18
15

In C++, use the const_cast as like below

char* str = const_cast<char*>("Test string");
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
appapurapu
  • 602
  • 7
  • 6
7

Test string is const string. So you can solve like this:

char str[] = "Test string";

or:

const char* str = "Test string";
printf(str);
Sicco
  • 6,167
  • 5
  • 45
  • 61
alexsid
  • 71
  • 1
  • 1
3

Just use type casting:

(char*) "test"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dario
  • 47
  • 1
  • 1
  • When a pointer is const, it points to something that **you should not (or cannot) change**. Casting it to non-const allows code to (try to) change it. Always fun to spend days finding out why e.g. a command stopped working, then discover that something modified the const keyword used in the comparison. – Technophile Dec 23 '21 at 05:04
  • @Technophile: There are many situations in which a pointer passed to a function will be used to produce a pointer that will be made available to the caller or code controlled thereby (e.g. given to a callback). An example from the standard library is `strchr()`. The `strchr()` function won't change the storage identified by the passed-in pointer, but it should have no reason to care about whether the caller will use the returned pointer to modify that storage. – supercat Apr 12 '22 at 16:39
  • @supercat are you arguing against const-correctness? Yes, strchr() (which violates const-correctness: a 30+ year old design error, fixed in the C++ version) doesn't 'care'; it's **code** and has no emotions. Caring is the **developer's** job. How does passing a pointer, or pointers derived from it, to other code invalidate const-correctness? – Technophile Apr 15 '22 at 22:09
  • 1
    @Technophile: If one has a function which receives a callback, and a data pointer which should be passed to the callback, it should be legal to pass const data to the function if the callback won't modify it, or to have the callback modify non-const data. If the calling code is supplying pointers to both the callback and its data, the calling code would be able to ensure they both agree, but if the calling code receives them from outside code, it would have no way of doing so. Const correctness would thus require duplicating a huge amount of code. – supercat Apr 16 '22 at 04:47
2

Do typecasting from constant string to char pointer i.e.

char *s = (char *) "constant string";
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
tejp124
  • 356
  • 3
  • 12
1

In C++, replace:

char *str = "hello";

with:

std::string str ("hello");

And if you want to compare it:

str.compare("HALLO");
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sohrab
  • 1,348
  • 4
  • 13
  • 33
1

I don't understand how to apply your solution :( – kalmanIsAGameChanger

Working with an Arduino sketch, I had a function causing my warnings.

Original function:

char StrContains(char *str, char *sfind)

To stop the warnings, I added the const in front of the char *str and the char *sfind.

Modified:

char StrContains(const char *str, const char *sfind).

All warnings went away.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • This is the correct answer as per the warning was saying: "warning: deprecated conversion from string constant to ‘char*’". – Mecanik Jul 22 '18 at 05:20
0

Just use the -w option for g++.

Example:

g++ -w -o simple.o simple.cpp -lpthread

Remember this doesn't avoid deprecation. Rather, it prevents showing warning message on the terminal.

Now if you really want to avoid deprecation, use the const keyword like this:

const char* s = "constant string";  
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Md. Arafat Al Mahmud
  • 3,124
  • 5
  • 35
  • 66
0

Picking from here and there, here comes this solution. This compiles clean.

const char * timeServer[] = { "pool.ntp.org" }; // 0 - Worldwide 
#define WHICH_NTP            0 // Which NTP server name to use.
...
sendNTPpacket(const_cast<char*>(timeServer[WHICH_NTP])); // send an NTP packet to a server
...
void sendNTPpacket(char* address) { code }

I know there's only one item in the timeServer array. But there could be more. The rest were commented out for now to save memory.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

While passing string constants to functions, write it as:

void setpart(const char name[]);

setpart("Hello");

Instead of const char name[], you could also write const char \*name.

It worked for me to remove this error:

[Warning] deprecated conversion from string constant to 'char*' [-Wwrite-strings]
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

You can also create a writable string from a string constant by calling strdup().

For instance, this code generates a warning:

putenv("DEBUG=1");

However, the following code does not (it makes a copy of the string on the heap before passing it to putenv):

putenv(strdup("DEBUG=1"));

In this case (and perhaps in most others) turning off the warning is a bad idea -- it's there for a reason. The other alternative (making all strings writable by default) is potentially inefficient.

Listen to what the compiler is telling you!

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
BillAtHRST
  • 35
  • 1
  • 8
    And it also leaks the memory allocated for that writable string. – RBerteig May 05 '09 at 20:55
  • 1
    Yes it does -- that's on purpose. Not a problem with one-time (e.g., initialization) code, as above. Or, you can manage the memory yourself and release it when you're done with it. – BillAtHRST Jun 20 '09 at 19:17
  • 1
    The particular case of [`putenv()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/putenv.html) is fraught — it is not a good choice of example (at least, not without a lot more discussion of what `putenv()` does than there is in this answer). It's a whole separate discussion. (Note that the POSIX specification for the behaviour of `putenv()` is problematic, based on the legacy implementations from before POSIX was defined.) IIRC, there was a bug in a recent (this millennium) release of GNU C Library that was related to `putenv()` behaviour changing, and being changed back.) – Jonathan Leffler Jun 29 '17 at 19:54
  • Also, it carries a comparatively huge performance penalty. – Peter - Reinstate Monica Jun 10 '21 at 11:38
-1

Use the -Wno-deprecated option to ignore deprecated warning messages.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
-1

See this situation:

typedef struct tagPyTypeObject
{
    PyObject_HEAD;
    char *name;
    PrintFun print;
    AddFun add;
    HashFun hash;
} PyTypeObject;

PyTypeObject PyDict_Type=
{
    PyObject_HEAD_INIT(&PyType_Type),
    "dict",
    dict_print,
    0,
    0
};

Watch the name field. Using gcc, it compiles without warning, but in g++ it will. I don't know why.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
shindow
  • 7
  • 2
  • 1
    gcc imply treat the file as C source file, g++ treat it as c++ source file, unless override by -x ?? option. So different language, c and c++ has subtle differences about what should be warning. – zhaorufei Jul 24 '17 at 19:27
  • This is a question, not an answer (Stack Overflow used as a forum). Someone even [attempted to answer it](https://stackoverflow.com/questions/59670/how-to-get-rid-of-deprecated-conversion-from-string-constant-to-char-warnin/10584743#10584743) (again, Stack Overflow being used as a forum). [Stack Overflow is not a forum](https://meta.stackoverflow.com/questions/36818/would-you-recommend-stackexchange-sites-vs-other-types-of-forum/36828#36828). – Peter Mortensen Oct 24 '22 at 22:53
-1

The problem right now is that I'm running with -Werror

This is your real problem, IMO. You can try some automated ways of moving from (char *) to (const char *) but I would put money on them not just working. You will have to have a human involved for at least some of the work. For the short term, just ignore the warning (but IMO leave it on, or it'll never get fixed) and just remove the -Werror.

James Antill
  • 2,825
  • 18
  • 16
  • 11
    The reason people use -Werror is so that warnings *do* get fixed. Otherwise they never get fixed. – Zan Lynx Jun 22 '10 at 23:18
  • 2
    The reason people use -Werror is because they've only worked on toy projects, or they are masochistic. Having your code fail to build because of a GCC update is a real problem when you have 100k+ LOC. Dito. someone adding junk like "-Wno-write-strings" to the build to get rid of the annoying warnings (like the highest rated comment in this post suggests). – James Antill Jun 23 '10 at 20:22
  • 2
    there is clear disagreement in that topic, for example http://programmer.97things.oreilly.com/wiki/index.php/Keep_the_Build_Clean – João Portela Nov 23 '10 at 23:00
  • 4
    @James: You make an interesting point, but there's got to be a better way. It seems pointless to not fix warnings immediately -- how do you recognize when new code has invoked a new warning when you haven't removed all of the old warnings? In my experience, that just leads to people ignoring warnings that they shouldn't be ignoring. – Brent Bradburn Jul 29 '11 at 22:44
  • 2
    @James: our toy project is 1.5+M LOC (multi-language). As nobar said, -Werror avoids ignoring warnings which should not be and yes, each time a new version of the compiler rises, we must recheck all. -Wno-write-strings is just used when using Boost for python wrappers in a file by file manner, because we are not going to rewrite Boost (and at now, 2017, we prefer to no more use Boost but C++11/cython). Each warning ignored must then be periodically reviewed by quality check to see if they can now be avoided by code or if it is not yet possible. – msn Feb 17 '17 at 11:34
  • 1
    `-Werror` was the difference between one of our customers threatening to cancel large contract, and 5-nines uptime. Some of the messages were meaningless stylistic issues; many were bugs-in-waiting. – Andrew Lazarus Jan 18 '19 at 23:09
-2

Re shindow's "answer":

PyTypeObject PyDict_Type=
{
    ...

PyTypeObject PyDict_Type=
{
   PyObject_HEAD_INIT(&PyType_Type),
                      "dict",
                      dict_print,
                      0,
                      0
};

Watch the name field. Using gcc, it compiles without warning, but in g++ it will. I don't know why.

In gcc (Compiling C), -Wno-write-strings is active by default.

In g++ (Compiling C++), -Wwrite-strings is active by default

This is why there is a different behaviour.

For us, using macros of Boost_python generates such warnings. So we use -Wno-write-strings when compiling C++ since we always use -Werror.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
msn
  • 128
  • 1
  • 4
  • Because of the change in revision 3, it *looked* like it plagiarised [shindow's answer](https://stackoverflow.com/questions/59670/how-to-get-rid-of-deprecated-conversion-from-string-constant-to-char-warnin/3553118#3553118), but in the first two revisions ************* ***it was quoted*** *************, clearly indicating it came from somebody else (so the formatting wasn't actually improved in revision 3...). – Peter Mortensen Oct 24 '22 at 22:48
  • But Stack Overflow was used as a forum here: First a follow-up question was posted in an answer and then it was answered here. – Peter Mortensen Oct 24 '22 at 22:48