I'm always wondering about the complaint of the compiler when I declare and define a char*-variable.
char* myChar = "Char";
The compiler will complain that it cannot convert const char* to char*. It need an explicit conversion like
char* myChar = (char*)"Char";
My first question is if this is the correct way to initialize a char* with a const char*. And my second question is, why the compiler need this explicit conversion. I think there is no great difference between const char* and char* except the const.
On a technical level, there is a great difference between const MyType* and MyType* and it is easier to see in your example char* myChar = "Char"; in that the litteral string can be part of memory that may not be changed, but by assigning that to a non-const pointer, you say that you may well planning to change some characters anyway. That behavior is undefined. It may work and it may make your program stop unexpectedly and you can't even rule out any other behavior.
By casting (prefer const_cast in C++), you are saying to the compiler that you know what you're doing and you know better. The normal solution is const char* myChar = "Char"; or even const char* const myChar = "Char"; if you're not planning to point to other char arrays.
In C++, I find it even clearer working with std::string if you want to work with strings.
To the advanced programmer, there is definitely a great difference between const and non-const, in terms of integrity, security, and performance.
We basically use const when we want to emphasize that a particular object/function/variable isn't allowed to be changed by the user.
check const correctness
The best-practice way to add/remove const/volatile modifiers is by using const_cast operator.
check The const_case operator
Related
I have a const uint8_t* that I want to convert to a char* for an interface that expects a char*.
The easiest way to do this is with a C-style cast:
const uint8_t* aptr = &some_buffer;
char* bptr = (char*)aptr;
However, our internal style guide (which is based on the Google C++ Style Guide) bans C-style casts.
Another option is this monstrosity, which I find pretty unreadable:
char *cptr = reinterpret_cast<char*>(const_cast<uint8_t*>(aptr));
These other options I tried all failed to compile:
char* dptr = reinterpret_cast<char*>(aptr);
char* eptr = const_cast<char*>(aptr);
char* fptr = static_cast<char*>(aptr);
Is there any way I can perform this cast using a C++-style cast without nesting two separate cast operations?
Is there any way I can perform this cast using a C++-style cast without nesting two separate cast operations?
Not portably, no. There is no single "the type is wrong and the const is also wrong" cast.
Another option is this monstrosity, which I find pretty unreadable:
char *cptr = reinterpret_cast<char*>(const_cast<uint8_t*>(ptr));
Do that.
Both C++ casts and your internal style guide are striving to make this look monstrous.
You can prevent the repetition of these casts by writing your own cast.
template< typename T >
char* awful_monster_cast( const T * ptr )
{
return reinterpret_cast<char*>(const_cast<T*>(ptr));
}
Is there any way I can perform this cast using a C++-style cast without nesting two separate cast operations?
If you want it done in a single line like char* foo = some_cast(source) then no. The only cast that can remove const is const_cast so you need that plus an additional one to convert that now non const pointer into your source type. That leaves you with the monstrosity
char *cptr = reinterpret_cast<char*>(const_cast<uint8_t*>(aptr));
as the single line solution. This is a safety feature and makes it so it is painfully obvious you are removing constness.
Another option is this monstrosity, which I find pretty unreadable:
char *cptr = reinterpret_cast<char*>(const_cast<uint8_t*>(aptr));
You might find it unreadable, but this is the idiomatic way to express this conversion in C++.
Here's what's important:
You are using a C-style API that, for whatever reason, is not itself const-correct, but you want to preserve the const-correctness of your own code, as much as possible, necessitating a cast to remove the cv-qualifications of the type.
The C-style API uses signed data types, whereas your application uses unsigned data types.
In total, those are two conversions that your code needs to make—removing the const-ness, and converting to a signed type. This demands that you make two explicitly expressed conversions, if you want to obey these coding practices. You may not agree with this principle, but your company/coding practices certainly do.
Of course, I don't think anything is stopping you from writing something like this:
char * convert_to_c_data_buffer(uint8_t const* ptr) {
return reinterpret_cast<char*>(const_cast<uint8_t*>(ptr));
}
char* dptr = convert_to_c_data_buffer(aptr);
Is there any way I can perform this cast using a C++-style cast without nesting two separate cast operations?
Certainly. There is no need to nest those cast operations. Instead, you can use two separate expressions:
auto cuint = const_cast<uint8_t*>(aptr);
auto cptr = reinterpret_cast<char*>(cuint);
I'm looking at some sample code for an API I'm about to start using. The following pattern has me a bit confused:
char* str;
str = const_cast<char*>("Hello World");
printf("%s ", str);
(actually there's a huge case statement in which str is assigned in each case.)
Note that printf takes const char*. Is there any reasonable purpose for this convoluted conversion? The authors of this code are applying lots of performance oriented tricks elsewhere, but there is no explanation for what's going on here.
My instinct is to change this code to:
const char* str;
str = "Hello World";
printf("%s ", str);
Am I missing something?
A string literal is a non-const char[N] in C, and a const char[N] in C++. Earlier versions of the C++ standard made special allowance for a const string literal to be assigned to a non-const char* for backwards compatibility with C. However, this behavior was deprecated in C++03 and is now illegal in C++11 without an explicit cast, such as the one shown.
If you are only interested in C++11, you should change str to const char*. Otherwise, you can use the cast for backwards compatibility.
The only possible reason could be that printf requires char* in some particular implementation. Which, after some research, seems not to be the case. On the other hand, having a pointer to non-const char pointing at a string literal is dangerous as modifying a string literal triggers undefined behavior. If it works without the cast there is no reason to have it there and you should change it rightaway.
The following code will print out the string:
char* test = "test";
std::cout << test << std::endl;
Although I do get this compiler (GCC) warning:
warning: deprecated conversion from string constant to 'char*'
Why do I not need to dereference the char pointer, to access the data? Also, why is what I have written deprecated, what should I use instead if I don't want a costly std::string object?
Why do I not need to dereference the char pointer
Because the iostreams classes have an overload for char* / char const*. Dereferencing it would only output a single char anyway.
Also, why is what I have written deprecated, what should I use instead
if I don't want a costly std::string object?
While it's highly unlikely using std::string will be detectibly "costly" in your program, you can change the type of test to char const*.
First off: the problem is in this line
char* test = "test";
a string literal is read-only data, so you should actually declare this as
const char* test = "test";
to make the compiler happy (i.e. I promise I won't try to modify that data, I'll be punished with undefined behavior if I do). That said, you don't need to dereference the pointer since there's a const char* overload to use that data. And this also answers you to the costly point (unless you meant something else).
Just want to know if there is a disadvantage of not using const_cast While passing a char* and simply type-casting it as (char *) or both are basically one and same ?
#include <iostream>
#include<conio.h>
using namespace std;
void print(char * str)
{
cout << str << endl;
}
int main ()
{
const char * c = "sample text";
// print( const_cast<char *> (c) ); // This one is advantageous or the below one
print((char *) (c) ); // Does the above one and this are same?
getch();
return 0;
}
Is there some disadvantage of using print((char *) (c) ); over print( const_cast<char *> (c) ); or basically both are same ?
First of all, your print function should take a const char* parameter instead of just char* since it does not modify it. This eliminates the need for either cast.
As for your question, C++ style casts (i.e. const_cast, dynamic_cast, etc.) are prefered over C-style casts because they express the intent of the cast and they are easy to search for. If I accidentally use an a variable of type int instead of const char*, using const_cast will result in a compile time error. However if I use a C-style cast it will compile successfully but produce some difficult to diagnose memory issues at runtime.
In this context, they are identical (casting from a "const char*" to a "char*"). The advantages of const_cast are:
It will help catch typos (if you accidentally cast a "const wchar_t*" to a "char*", then const_cast will complain.)
It's easier to search for.
It's easier to see.
The C-style cast (char *) is equivalent if used properly. If you mess up the const_cast, the compiler will warn you, if you mess up the C-style cast you just get a bug.
const_cast is more appropriate because it only casts away constness, and otherwise will warn you about other possible mistakes (like converting one pointer type to another etc), and (char *) will just silently interpret anything you give it as char *. So if you can - better use const_cast for better type safety.
Independently on the effect that C cast do in this particular case, C cast and C++ casts are not the same: C++ distinguish between reinterpret, static, dynamic and const cast.
The semantics of these cast are different and not always equally possible.
C cast can be either static or reinterpret cast (where static is not possible). It must be used where such an ambivalence is a requirement (I cannot imagine how and when), it must be avoided where a well defined and expected behavior is needed.
In Java, we can specify a string as final to declare 'constants'. For example
static final String myConst = "Hello";
Is the correct way to do this in c++ like this?
const char * const myConst = "Hello";
I've always seen people do this:
const char * myConst = "Hello";
But, actually, you can change what that pointer points to. So, why do people not declare the pointer as constant as well? What is the correct way to do it?
const std::string myConst("Hello");
Yes, const char* const is the correct way to declare a C-style string which you will not change.
Or better:
#include <string>
const std::string myConst = "Hello";
const char * myConst = "Hello";
This means the object pointed at cannot change.
char * const myConst = "Hello";
This means the location pointed at by the pointer cannot change, but the object's value can.
const char * const myConst = "Hello";
This means neither may change. In my experience no one remembers this, but it's always available on the net!
Typical, three people answer in the time I write mine!
I don't exactly understand your question. To more or less mimic the final Java keyword, it would be either
const char * const myConst = "Hello";
(if the pointer is not going to change), and/or:
const char * myConst = "Hello";
if the pointer may change afterwards. Finally, note that with the first version, you cannot actually change the pointer itself, because it is constant.
With Diego's edit, yes, that the right way to write it. People typically don't declare the variable const because they don't care whether it will be modified, or, rather, trust that it won't be modified (since they know they don't modify it).
They declare the pointed-to const because a string literal really has const characters, so you really must assign it to a variable that has char const * values.
Technically,
char * const myConst = "Hello";
is the most correct answer, as reassigning the pointer would leave you with a string which probably could not be recovered.
Some implementations allow you to change the characters in "Hello" (even if it's a bad idea), so the first const in
char const * const myConst = "Hello";
Is a great idea. Personally as
char const * myConst = ...;
and
const char * myCount = ...;
are equivalent, I tend to enforce a style guideline that the const always follows the item it modifies. It sometimes reduces misconceptions in the long run.
That said, most people don't know how to use const correctly in C++, so it's either used poorly or not at all. That's because they just use C++ as an improved C compiler.
But, actually, you can change what
that pointer points to. So, why do
people not declare the pointer as
constant as well? What is the correct
way to do it?
Because it's rarely useful, more often than not you would want to have the values on the stack (pointers included) to be non-const. Get Sutter & Alexandrescu "Coding Standards" book, it explains this point.
The real point is that programmers are compeled to declare some pointers at least as const char * to store char arrays between double quotes. Nothing force them (no compiler warning or error) to also make the pointer constant... as people are lazy you can draw your own conclusion. They are probably not even really trying to define a constant, they just want to shut off compiler errors (well, warning in this case).
Keeping that in mind, I would probably go for a different solution anyway:
const char myConst[] = "Hello";
The difference here is that this way I won't decay the original byte array used as string to a pointer, I will still have a byte array that can be used exactly as the original literal.
With it I can do things like sizeof(myConst) and get the same result as with sizeof("Hello"). If I change string to a pointer, sizeof would return the size of a pointer, not the size of the string...
... and obviously when doing things this way changing the pointer becomes meaningless, as there is no pointer to change anymore.