开发者

Is it possible to completely avoid C-style casts in C++?

开发者 https://www.devze.com 2023-01-25 15:45 出处:网络
I do not believe that it is possible to completely avoid C-style casts when writing C++. I was surprised to find out that I needed to use a C-style cast to avoid a compiler truncation warning:

I do not believe that it is possible to completely avoid C-style casts when writing C++. I was surprised to find out that I needed to use a C-style cast to avoid a compiler truncation warning:

short value_a = 0xF00D;                     // Truncation warning in VS2008
short value_b = static_cast<short>(0xF00D); // Truncati开发者_StackOverflow社区on warning in VS2008
short value_c = (short)0xF00D;              // No warning!

Are there other scenarios where there is no C++-style substitute for a C-style cast?


In C++, the C-style cast is defined (§5.4) in terms of C++-style casts. So for every cast you can do C-style, there's a matching C++-style cast (almost).

The "almost" is that C-style casts ignore base class accessibility. That is, there is no equivalent C++-style cast for the following:

struct foo {};
struct bar : private foo {};

bar b;
foo* f = (foo*)&b; // only way this can be done in a well-defined manner

So, no it's not strictly-speaking possible to completely ditch C-style casts. But the number of areas where a (combination of) C++-style casts doesn't suffice is few in count.


The above is the "language answer". What you're experiencing has nothing to do with C-style casts versus C++ casts, but just compiler implementation. Warnings are absolutely implementation-specific, and have nothing to do with C++.

So don't make the mistake of using your findings on this particular compiler in this particular situation for concluding things about C++ in general.


You are just trying to obfuscate your code, it is as simple as that. And the compiler is completely correct in telling you so.

If you have a precise idea what the assigned value should be, use that. My guess is that you have some unfounded presumption of short being 16 bit wide and that the sign representation of the target machine is two's complement. If that is so, assign -4083 to your variable. If you just need your variable as a bit vector, use an unsigned type.

As far as C is concerned the standard simply says about conversion from one integer type to another:

Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

I imagine the the point of view of C++ with this respect is not much different. Other answers mention border cases where in C++ you would need a `C'-style cast to overrule all typechecks that C++ gives you. Feeling the need for them is an indication of bad design.

The case that you give as an example is certainly not one for which I would find any valid circumstances.


Yes, it is completely possible.

I never use C-style casts. I can write hundreds of thousands of lines of code without having to revert to using reinterpret_cast, C++'s closest cousin to the C-style cast. The only times I have to use reinterpret_cast is when doing socket programming -- a fairly narrow domain, in the big picture.

You don't need to use C-style casts, either. In your other post, you said

I could just use a negative value,

short my_value = -4083;

but in my code it is much more understandable to use hexadecimal.

So in this case you didn't have to use the cast. You chose to.


There are 4 c++ style casts, const_cast, reinterpret_cast, static_cast and dynamic_cast. They work as follows:

// const_cast casts away constness or adds it
const int const_integer = 5;
const_cast<int>(const_integer) = 3;

// static_cast will perform standards defined casts and will 
// cast up or down a c++ inheritance hierarchy without checking the result of the cast
struct b {};
struct a : public b {};
struct c {};
double value = static_cast<double>(0.0f);
b* b_value = new b;
a* a_value = static_cast<a*>(b_value);

// dynamic_cast will perform any cast that static_cast will, but will check to see
// if the cast makes sense. If the values are not pointers, this cast can throw
b* value_b = new b;
a* value_a = new a;
b* new_b = dynamic_cast<b*>(value_a); // will return NULL
a* new_a = dynamic_cast<a*>(value_b); // will not return NULL    

// reinterpret_cast will change any type to any other type, as long as the constness of the types is the same.
// the behavior of this cast is implementation specific.
double* a = new double;
*a = 0.0f;
int *b = reinterpret_cast<int*>(a);

A c-style cast in c++ simply tries to perform those casts in a specific order until one of them works. That order is as follows:

  • a const_cast
  • a static_cast
  • a static_cast followed by a const_cast
  • a reinterpret_cast, or
  • a reinterpret_cast followed by a const_cast.

So, in short, you can do any c-style cast in c++, because a c-style cast in c++ is just some arrangement of c++ style casts. Get it?


I was surprised to find out that I needed to use a C-style cast to avoid a compiler truncation warning

I see it the other way around: You use a C-style cast to prevent the compiler from warning you, and I see this as a severe disadvantage of the C-style cast.

if you feel you know what you're doing, then shut up the compiler for this one case by using a compiler-specific way. For example, for VC use something like

#pragma warning(push, disable: XXXX)
// code goes here
#pragma warning(pop)


In these cases, you can use reinterpret_cast. It was meant for a replacement of a unchecked C-style cast. The typical note here: this is unchecked cast, and should be avoided when possible by using the other available: const_cast, dynamic_cast, etc.

0

精彩评论

暂无评论...
验证码 换一张
取 消