Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are
spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the
password reset link.
Entire forum
➜ ROM
➜ Compiling the server
➜ warning: deprecated conversion from string constant to 'char*'
warning: deprecated conversion from string constant to 'char*'
|
It is now over 60 days since the last post. This thread is closed.
Refresh page
Posted by
| Robert Powell
Australia (367 posts) Bio
|
Date
| Sat 24 Oct 2009 04:02 AM (UTC) |
Message
| Ok, does anyone have a proper solution to deal with warning: deprecated conversion from string constant to 'char*' warnings in G++ code other than suppressing the warning.
Thanks. |
Just a guy having a bit of fun. Nothing more, nothing less, I do not need I WIN to feel validated. | Top |
|
Posted by
| Worstje
Netherlands (899 posts) Bio
|
Date
| Reply #1 on Sat 24 Oct 2009 05:48 AM (UTC) |
Message
| The solution depends on the situation.
A constant is a constant, and thus cannot be changed. A char* parameter is a pointer to a(n array of) char(s), and can thus be changed from within the function that has it as a parameter. Thus, if you feed it a constant, and it tries to modify it, you'll get a crazy-ass segfault.
If the function is not meant to be modifying what you pass to it, change the parameter to a const char* and the error will disappear.
If the function -is- meant to change what you pass to it, you simply can't pass a string constant to it. Allocating an array of chars and strcpy()-ing your constant into it, and then passing said array to the function is the other solution. | Top |
|
Posted by
| Nick Gammon
Australia (23,046 posts) Bio
Forum Administrator |
Date
| Reply #2 on Sat 24 Oct 2009 06:13 AM (UTC) Amended on Sat 24 Oct 2009 06:14 AM (UTC) by Nick Gammon
|
Message
| Well it isn't really valid to coerce "const char *" to "char *", particularly with string literals. For one thing, once it becomes char *, and pass it to a function, that function can validly change it. Now for a literal, which is likely to be shared amongst various places, this might result in changing "dog" to "cat" not just once, but everywhere in the program.
Another problem is that literals are likely to be in protected memory, so it will crash if you attempt to change it.
Basically, what you need to do is, if you are passing a literal down to a function, that function should be taking a const char * argument, not a char * argument.
However this can be fiddly to get right, as you then find that if this function calls other functions, they also need to be changed and you get a knock-on effect. Plus, sometimes you actually want to pass down char * data (eg. something the player types), so making it take the const form can then break other things.
If you are using C++ and not C, you might be able to use the string class to work around this. For example, instead of:
void my_func (char * s) { blah }
you might have:
void my_func (string s) { blah }
For example:
#include <iostream>
#include <string>
using namespace std;
void my_func (char * s)
{
cout << s << endl;
}
int main (void)
{
my_func ("nick");
return 0;
}
Compiles with:
test1.cpp: In function ‘int main()’:
test1.cpp:14: warning: deprecated conversion from string constant to ‘char*’
However:
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
void my_func (string s)
{
cout << s << endl;
}
int main (void)
{
char s1 [] = "hello there";
char s2 [100];
strcpy (s2, "testing");
my_func ("nick");
my_func (s1);
my_func (s2);
return 0;
}
That compiled without warnings, and printed all 3 strings. Once you have a string (as in, the string class) you can convert back to const char * with the c_str function. For example:
string s3 = "test";
printf ("%s\n", s3.c_str ());
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Robert Powell
Australia (367 posts) Bio
|
Date
| Reply #3 on Sat 24 Oct 2009 12:32 PM (UTC) |
Message
| Thanks Nick, that makes a whole lot of sense, the code i have been asked to look at and clean up has been somewhat converted to g++ and there are literally 1000's of these warnings.
Ultimately this looks like a rock and a hard place situation where i am going to have to spend hours fixing each and every location, how you mentioned it above. |
Just a guy having a bit of fun. Nothing more, nothing less, I do not need I WIN to feel validated. | Top |
|
Posted by
| David Haley
USA (3,881 posts) Bio
|
Date
| Reply #4 on Mon 26 Oct 2009 02:39 AM (UTC) |
Message
| You can look at what I did for SmaugFUSS to fix these warnings. It's a little tedious, but basically you need to make sure that if a function doesn't modify a char* argument, that the argument becomes a const char*. If the function absolutely must modify it, you should see if you can get away with a temporary local copy, or if the caller should be taking care of passing in a modifiable copy. For the vast majority of cases, it's quite clear what you need to change; there are just a handful of places where you need to be careful, typically in making sure that you create and destroy temporary copies appropriately.
If you're going to take the std::string approach, your parameters should be const std::string&, not just std::string. Although it makes no difference if you're passing in char* pointers -- the std::string must be constructed regardless -- it will make a difference if/when you have more std::strings lying around, because you will not be needlessly copying them. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | Top |
|
Posted by
| Robert Powell
Australia (367 posts) Bio
|
Date
| Reply #5 on Mon 26 Oct 2009 03:33 AM (UTC) |
Message
| Thanks David, i have not actually begun on this part of my G++ ROM odyssey as im am a little apprehensive when it comes to making wholesale changes that i don't really understand.
I think which keeping with the G++ experience i would end up going down the std::string path, as it may serve me better in the long run, for now i have suppressed the warnings, however i would like to look at some sample code that has done this already, do you have any suggestions that i should look at. |
Just a guy having a bit of fun. Nothing more, nothing less, I do not need I WIN to feel validated. | Top |
|
Posted by
| David Haley
USA (3,881 posts) Bio
|
Date
| Reply #6 on Mon 26 Oct 2009 04:30 AM (UTC) |
Message
| Yes. As I said, I went through the SmaugFUSS code and fixed these warnings by handling constness correctly. You can simply look at the most recent version of SmaugFUSS to see how constness was respected; a lot of the code overlaps with ROM as far as I know. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | Top |
|
Posted by
| Nick Gammon
Australia (23,046 posts) Bio
Forum Administrator |
Date
| Reply #7 on Mon 26 Oct 2009 04:40 AM (UTC) |
Message
| I didn't use the & feature (ie. make it pass by reference) because I wasn't sure a literal string would be converted to a reference, but it appears David is right. You can change the function in my example to:
void my_func (const string & s)
{
cout << s << endl;
}
That still compiles and runs OK. (Not sure why, perhaps the compiler makes a temporary string object on the stack, and passes that by reference). |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Nick Gammon
Australia (23,046 posts) Bio
Forum Administrator |
Date
| Reply #8 on Mon 26 Oct 2009 04:43 AM (UTC) |
Message
|
Robert Powell said:
I think which keeping with the G++ experience i would end up going down the std::string path, as it may serve me better in the long run ...
Yes, using the string class instead of char arrays saves a lot of stuff like:
... which is basically allocating large strings all over the place "just in case" someone passes a long string into it. And still it might fail if the string coming in is larger than MSL. Using the string class is more efficient for small cases, and won't fail for large ones. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| Nick Gammon
Australia (23,046 posts) Bio
Forum Administrator |
Date
| Reply #9 on Mon 26 Oct 2009 04:45 AM (UTC) |
Message
| And technically, the language is C++, the compiler is the g++ compiler (note capitalisation).
From the man page (man g++) it says:
gcc - GNU project C and C++ compiler
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| David Haley
USA (3,881 posts) Bio
|
Date
| Reply #10 on Mon 26 Oct 2009 04:48 AM (UTC) |
Message
|
Nick Gammon said: (Not sure why, perhaps the compiler makes a temporary string object on the stack, and passes that by reference).
Yes, exactly. When you have a function f:
void f(SomeType arg) { ... }
and then you call it:
SomeOtherType val;
f(val);
then the compiler will try to convert SomeOtherType to SomeType, which can mean calling a SomeType constructor that takes a SomeOtherType as an argument. In this case, std::string has a const char* constructor, so the compiler calls that. The newly-constructed object is discarded once the call is complete. In this case, the temporary object is constructed, and then passed by reference, and finally destroyed.
This is one reason why it's occasionally good to have versions of a function for likely input parameters (e.g., const char* and std::string) because if you can avoid creating the std::string, you should (assuming efficiency matters in the context). |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | Top |
|
Posted by
| Nick Gammon
Australia (23,046 posts) Bio
Forum Administrator |
Date
| Reply #11 on Mon 26 Oct 2009 05:24 AM (UTC) Amended on Mon 26 Oct 2009 05:51 AM (UTC) by Nick Gammon
|
Message
| By which David means this could work for you:
#include <string>
#include <string.h>
using namespace std;
void my_func (const char * s)
{
printf ("I got %s\n", s);
}
void my_func (const string & s)
{
my_func (s.c_str ());
}
int main (void)
{
char s1 [] = "hello there";
char s2 [100];
strcpy (s2, "testing");
my_func ("nick");
my_func (s1);
my_func (s2);
return 0;
}
Now there are two my_func functions, one will take a const char *, and one a const string, depending on what is required.
Interestingly, when I added a debugging line, all of the calls used the first my_func, so the compiler must have decided to convert char* to const char* rather than const string &.
I suppose this is because it is alright to add const-ness, but not to take it away. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|
Posted by
| David Haley
USA (3,881 posts) Bio
|
Date
| Reply #12 on Mon 26 Oct 2009 01:14 PM (UTC) |
Message
| Yeah, there are a series of rules about which conversions to prefer. I don't remember the exact phrasing of the rule, but it has to do with making the least amount of changes. Exact matches are preferred, and then "nearer" matches are preferred. So adding constness is "closer" than converting to another type (which makes sense really). But IIRC if it could be converted to two types, the compiler will complain about an ambiguous overload. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | Top |
|
The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).
To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.
41,266 views.
It is now over 60 days since the last post. This thread is closed.
Refresh page
top