ChatGPT解决这个技术问题 Extra ChatGPT

How to get rid of `deprecated conversion from string constant to ‘char*’` warnings in GCC?

So 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?

When you do come to tackle replacing 554 lines, sed is a good friend. Make sure you back up first though.
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.
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 stackoverflow.com/questions/56522654/….
564 files is entirely doable. Just do it. (Well, in all likelihood you have done it by now ;-) ).

p
phoenix

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;
}

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.
@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.
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.
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
I don't understand how to apply your solution :(
T
Tim Cooper

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


Is it can be disabled on per file basic using pragmas.
@PriyankBolia bdonlan commented on Rob Walker's answer that it can using #pragma GCC diagnostic ignored "-Wwrite-strings".
Except if you control the API, in which case @John's answer below, about changing the signature to accept const char*, is more correct.
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.
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 !
L
LogicStuff

I had a similar problem, 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);
}

Is this an appropriate way of solving this? I do not have access to foo to adapt it to accept const char*, although that would be a better solution (because foo does not change m).


@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.)
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.
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};
@elcuco: I'm not sure how C++ static arrays work. Will this really copy any data, and not just pointer ?
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.
C
Community

Check out gcc's Diagnostic Pragma support, and the list of -W warning options (changed: new link to warning options).

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


It does actually: #pragma GCC diagnostic ignored "-Wwrite-strings"
This answer doesn't actually contain the answer.
K
Konrad Rudolph

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.


that does only solves declarations warnings and not function calls +1 for sed fu anyway :p
E
EdH

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

v
vy32

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

char *setf = tigetstr("setf");

to this:

char *setf = tigetstr((char *)"setf");

+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.
The thing that is really annoying is that tigetstr() should be prototyped with a (const char *), not a (char *)
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")
I think the const cast is the first acceptable solution on this page (except the API change).
L
LogicStuff

Replace

char *str = "hello";

with

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

or if you are calling in function:

foo("hello");

replace this with

foo((char*) "hello");

g
gipinani

Instead of:

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

This works:

void foo(const char s[]);
foo("constant string");

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!
L
LogicStuff

In C++, use the const_cast as like below

char* str = const_cast<char*>("Test string");

S
Sicco

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

char str[] = "Test string";

or:

const char* str = "Test string";
printf(str);

L
LogicStuff

Why not just use type casting?

(char*) "test"

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: 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 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: 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.
L
LogicStuff

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

char *s = (char *) "constant string";

S
Sohrab

In C++, Replace:

char *str = "hello";

with:

std::string str ("hello");

And if you want to compare it:

str.compare("HALLO");

M
MyGEARStationcom

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

Working with 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.


This is the correct answer as per the warning was saying: "warning: deprecated conversion from string constant to ‘char*’".
s
svick

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, in gcc it compile without warning, but in g++ it will, i don't know why.


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.
J
Jason Plank

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!


And it also leaks the memory allocated for that writable string.
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.
The particular case of putenv() 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.)
Also, it carries a comparatively huge performance penalty.
M
Md. Arafat Al Mahmud

just use -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 const keyword like this:

const char* s="constant string";  

D
Drew Noakes

Why don't you use the -Wno-deprecated option to ignore deprecated warning messages?


M
Micheal Morrow

Thanks, all, for the help. Picking from here and there comes this solution. This compiles clean. Have not tested the code yet. Tomorrow... maybe...

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 1 item in the timeServer array. But there could be more. The rest were commented out for now to save memory.


A
AAEM

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]

R
Ramarajan
PyTypeObject PyDict_Type=
{ ...

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

watch the name field, in gcc it compile 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


J
James Antill

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.


The reason people use -Werror is so that warnings do get fixed. Otherwise they never get fixed.
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).
there is clear disagreement in that topic, for example programmer.97things.oreilly.com/wiki/index.php/…
@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.
@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.