katang
katang

Reputation: 2764

What is the difference between two 'char*' castings in c++

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

Answers (3)

AndersK
AndersK

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

Chris
Chris

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

AnT stands with Russia
AnT stands with Russia

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

Related Questions