Reputation: 2764
I do have a "C" function
find_register(char *name)
which is called from a "C++" routine. The first tip to call it was
find_register("%ebx")
It results in a warning
deprecated conversion from string constant to 'char*'
OK, I corrected it to
find_register(string("%ebx").c_str())
which results in the error message
"invalid conversion from 'const char*' to 'char*'
Finally,
find_register((char*)string("%ebx").c_str())
is accepted without error message and warnings.
My questions: 1./ The probable reason of the error message is that the possibility of changing a 'const char*' is left open. It is OK, but in the first case the less sophisticated version allows the same, and converting a string constant to 'char *' is a legal, but deprecated conversion. Is there any deeper reason behind?
2./ Is there any simple method to do what I want? (the perfect (for the compiler) code is hardly readable for the programmer)
Upvotes: 2
Views: 129
Reputation: 36082
The prototype for the function find_register(char*)
indicates that it may change the parameter since it is just a pointer that is passed. You do not mention if you have the source code of that function so I assume you don't otherwise it would be better to change that function to accept a char const *
provided it doesn't change the contents.
Otherwise just pass a modifiable array:
char arg[] = "%ebx";
find_register(arg);
to write:
find_register((char*)string("%ebx").c_str())
is dangerous, what if the function does indeed modify the string e.g. strtok
? But if you insist at least try to use the C++ style of casting instead of C casting (in this case find_register(const_cast<char*>("%ebx"))
).
Side note: personally I find it easier to read to avoid using the C-way of putting const when possible. So instead of writing const char *
write char const *
and char * const
when the pointer is constant i.e. const always goes to the left - it is more consistent.
Upvotes: 2
Reputation: 1623
If you are passing string literals to find_register(char *name)
, then the function prototype should be find_register(const char *name)
, as string literals are not modifiable.
With this conversion, C++ will happily let you shoot yourself in the foot and try to modify name
, which gives me a segmentation fault, as in the following code:
void modifyIllegally(char* name) {
name[0]='d';
}
int main() {
modifyIllegally("abc");
}
Edit: If you don't control the API of the C program and are sure it won't change the char*
, you can disable this warning with compiler flags. For gcc the flag is -Wno-write-strings
.
Upvotes: 1
Reputation: 320361
The reasoning lies in the original roots of C++ language, back in the time when certain amount of backward compatibility with C was considered important.
In C language string literals, despite being non-modifiable, have type char [N]
. For this reason they are implicitly convertible to type char *
in C. In C++ string literals have type const char[N]
. Formally, const char[N]
is not implicitly convertible to char *
. But for aforementioned C compatibility reasons the original C++ specification (C++98) allowed implicit conversion of string literals to char *
. This exception was made for immediate string literals only, as a form of special treatment provided to string literals.
But eventually the matter of C compatibility became unimportant and this special treatment was deprecated in C++03. So, this is what the compiler is telling you. In your find_register("%ebx")
call it agrees to convert the immediate string literal to char *
, but warns you that this conversion is deprecated. In C++11 this implicit conversion is outlawed entirely.
In all other contexts (not an immediate string literal), implicit conversion of const char [N]
or const char *
to char *
is prohibited and has always been prohibited. This is why your
find_register(string("%ebx").c_str())`
variant has no chance of compiling.
As for working around this restriction... If you are sure that find_register(char *name)
does not attempt to change the data pointed by name
(and you cannot just change the find_register
's parameter type to const char *name
), then
find_register(const_cast<char *>("%ebx"))
is a fairly acceptable solution (with an appropriate accompanying comment). Of course, if find_register
is a modifying function, then you'll have to do something like
char reg[] = "%ebx";
find_register(reg);
Upvotes: 11