简体   繁体   中英

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)

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

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 eg 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 ie const always goes to the left - it is more consistent.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM