Common advice when writing C++ states that implicit conversions should be avoided in favour of explicit casts.
int x = myUnsignedLongVar; // should be avoided
while
int x = static_cast<int>(myUnsignedLongVar); // is preferred
Does a static_cast make this conversion any safer? As far as I'm aware both conversions are implementation defined?
Is the static_cast just a signal to indicate more verbosely that this operation is potentially implementation defined?
And who's implementation? Is the operation dependent on the implementation of the compiler or the CPU?
Both examples would produce the same code.
But, in the second one everyone knows that there’s a cast to int.
In the first one could assume myUnsignedLongVar is int.
In order to make sure nobody misses the cast, guidelines and compilers recommend making it explicit.
I believe your example is somewhat narrow to show the real difference between different types of casting.
If you are simply casting from unsigned int to int, or from double to int, this may not show its real value.
The real value comes when you do not want to allow casting to cause bugs in your program. For example when performing comparisons between signed and unsigned types, or pointer or changing object types. Moreover, C++ style casting i.e. static cast is checked by the compiler.
Another benefit is what you already mentioned. Verbosity. They ensure that the authors intent is captured.
Several answers to this question contain a nice summary and comparison between different types of casting.
Related
Why is my static_cast of a pointer failing?
int iDog = 456;
int *piDog = &iDog;
long *plDog = static_cast<long*>(piDog); // invalid type conversion
long lDog = static_cast<long>(iDog); // ok
long* plDog = (long*)(piDog); // this is OK too... very weird!! (Dynamic cast... and we aren't allowed to use this one in our coding standards)
This reference suggests it should be OK: https://en.cppreference.com/w/cpp/language/static_cast
Issue with Visual Studio C++?
long *plDog = static_cast<long*>(piDog); // invalid type conversion
Why is my static_cast of a pointer failing?
Because it is ill-formed. None of the rules of static_cast apply to the cast that you're attempting. It is an invalid conversion, as you mention in the comments.
A pointer to one object type may not be static casted to a pointer to another object type unless they are pointers to related classes, or when casting to/from pointer to void.
This reference suggests it should be OK: https://en.cppreference.com/w/cpp/language/static_cast
That reference suggests that the conversion you attempt is not OK.
long* plDog = (long*)(piDog); // this is OK too... very weird!!
This is a well-formed conversion. It's not "weird".
There are many conversions that explicit conversions (also called "cast notation" or "C-style cast") allow, and static casts do not allow. This is because static casts have (at least a semblance of) type safety while explicit conversions essentially ask the compiler to pretend that the type system doesn't exist.
Note that indirecting through plDog and accessing the object would result in undefined behaviour. As you can see, it was a good thing that you got the error.
and we aren't allowed to use this one in our coding standards
This is a good limitation to have. This will make it bit harder for your team to write bugs by mistakenly circumventing the type system.
Issue with Visual Studio C++?
No, the issue is that the program is ill-formed. The compiler is correct to inform you about the bug, and is not required to compile the program.
I recommend asking yourself: Why do you want to, or think that you need to do such cast?
TL;DR: If your cast worked, the language would provide no type-safety guarantees for pointers, and is a key part of the motivation for introducing the C++ style casts instead of sticking with the old-school C cast.
In the language of the C/C++ Standard, long* and int* are not "pointer-compatible". You can't implicitly convert a long* to an int* or vice-versa, so static_cast can't do it in a single cast.
The reasoning behind that is sizeof(long) is not always equal to sizeof(int) for all platforms. They are distinct fundamental types. This is true in general of all distinct C/C++ types even if they have an identical binary layout. They are only "pointer-compatible" if in the syntax of the language you declare the types to be related via implicit conversion.
You can use static_cast when converting from a void* to any pointer to an object type or vice-versa.
Therefore you can do this in two ways:
reinterpret_cast<long*>(piDog);
-or-
static_cast<long*>(static_cast<void*>(piDog));
Stylistically, the use of the reinterpret_cast is a lot clearer. In either case, the validity of the cast is architecture dependent and assumes sizeof(int) == sizeof(long) as well as having the same memory layout.
IOW This is safe for Windows x86 and x64 native, but may not hold for other platforms or CPUs. This is one of the reasons Windows x64 choose to use the LLP64 data model as explained in this blog post.
See cppreference for static_cast and reinterpret_cast
I'm working on an existing code base, so the answer "do it right, just use one type" doesn't work because they already didn't do it right, I just have to live with it.
I know that coercion works so that this works:
int a = 1;
long b = a;
even though int and long are different base types. However, this doesn't work:
int a;
long *b = &a;
because there's no auto conversion between "pointer to int" and "pointer to long".
If, rather than base types, I was working with classes, I could get it to work by providing a conversion. My question is this. Is there a way to provide conversions for base types (or rather pointers to base types) so I could start the process of converting my code to use a single 32-bit integral type? As it stands, I either need to do an "all or nothing" edit OR provide a boatload of explicit casts.
My question is this. Is there a way to provide conversions for base types (or rather pointers to base types) so I could start the process of converting my code to use a single 32-bit integral type?
No, there is no way to influence the set of implicit conversions between pointer types aside from inheritance relations between classes.
Even if you add a (long*) cast or reinterpret_cast<long*> everywhere, as mentioned in the comments, accessing the value through that pointer will be an aliasing violation and therefore cause undefined behavior. This is not related to the size, alignment or the representation of the int and long types. Rather compilers are explicitly allowed to make optimizations that assume that a long pointer can never be pointing to a int object and compilers will perform such optimizations that will break code in possibly very subtle ways.
Note that this is different for casts between e.g. signed int* and unsigned int*. Signed and unsigned variants of the same integral type are allowed to alias one another, so that either pointer type can be used to access the object. The compiler is not allowed to perform optimizations in this case that assume that pointers of the two types don't point to the same address at the same time.
GCC and Clang offer the -fno-strict-aliasing option to disable optiizations based on the aliasing rules (still assuming that the type do actually have the same size, alignment and compatible representations), but I don't know whether MSVC has a similar option. Some compilers may also explicitly allow additional types to alias that the standard does not allow to alias, but I would only rely on that if the compiler documents these clearly. I don't know whether MSVC makes any such guarantees for int and long.
Or equivalently
reinterpret_cast<int64>( aDoubleValue )
Allowing such a reinterpret_cast would not introduce any aliasing issues.
I understand that using memcpy to replicate bytes from a variable of one type into a variable of another type can achieve the necessary effect. And I understand that mature compilers with powerful optimizers can do wonderful things with such memcpy constructs.
That said I happen to be a compiler-writer. I am very aware of the many forms of optimization that must exist and the many preconditions that have to be met in order to pull off those dramatic optimizations. Do we really want to assume that every compiler is that powerful or that every programmer will write code successfully satisfying all of the necessary preconditions? Can we really fault programmers using non-mainstream compilers for being dubious that such a hoped-for optimization will occur?
The need to inspect the bits of a floating point values arises fairly often. Do we really want to insist that every programmer encountering such a need traffic in address-taken variables, char* exceptions to type aliasing rules, memcpy magic, etc?
The "new" (now pretty old) forms of casting provided in C++ are all basically subsets of things you can do with C-style casts ("basically" because they have a few minor additions like dealing with references, that just don't exist in C).
To get the equivalent of a reinterpret_cast with a C-style cast, you do something like:
int a = *(int *)&some_float;
So, with a reinterpret_cast, you do pretty much the same things, just changing the syntax for the cast itself with a reinterpret_cast instead:
int a = *reinterpret_cast<int *>&some_float;
As for defining what this does, so you can do it without violating any strict aliasing rules and such: I suspect the committee would probably be happy to consider a really well written proposal--I suspect the problem right now is that most think it would take a lot of work, and payoff would be minimal.
If the real intent is to support looking at the bits of a floating point number, it might be simpler to define something like a constructor for a bitset::bitset<float> or something on that order, to give a type that's already explicitly defined to give access to bits (though it would still probably be non-trivial to define how it's supposed to work in a way that's at all portable).
If all you want is a function that converts a float into its sequence of bits, memcpy can do that without running afoul of the strict aliasing rule:
unsigned int ConvertFloat(float f)
{
unsigned int ret;
std::memcpy(&ret, &f, sizeof(unsigned int));
return ret;
}
Live example.
You could even make a general template function for converting one type to another. One that would static_assert or SFINAE-check if the arguments are trivially-copyable.
In your line of work, converting floats to integers is a semi-frequent operation. But that's simply not true for most C++ users (or even most C users). So there is no widespread need for such a conversion operation.
Furthermore, the C++ standard doesn't require an implementation to provide any particular representation of a float. So even if the standard provided such a function, it couldn't tell you what it actually returned. There's not even guarantee that float can fit into an unsigned int.
This question concerns something I noticed in the C++ spec when I was trying to answer this earlier, intriguing question about C-style casts and type conversions.
The C++ spec talks about C-style casts in §5.4. It says that the cast notation will try the following casts, in this order, until one is found that is valid:
const_cast
static_cast
static_cast followed by const_cast
reinterpret_cast
reinterpret_cast followed by const_cast.
While I have a great intuitive idea of what it means to use a static_cast followed by a const_cast (for example, to convert a const Derived* to a Base* by going through a const_cast<Base*>(static_cast<const Base*>(expr))), I don't see any wording in the spec saying how, specifically, the types used in the static_cast/const_cast series are to be deduced. In the case of simple pointers it's not that hard, but as seen in the linked question the cast might succeed if an extra const is introduced in one place and removed in another.
Are there any rules governing how a compiler is supposed to determine what types to use in the casting chain? If so, where are they? If not, is this a defect in the language, or are there sufficient implicit rules to uniquely determine all the possible casts to try?
If not, is this a defect in the language, or are there sufficient implicit rules to uniquely determine all the possible casts to try?
What about constructing all types that can be cast to the target type using only const_cast, i.e. all "intermediate types"?
Given target type T, if static_cast doesn't work, identify all positions where one could add cv-qualifiers such that the resulting type can be cast back to T by const_cast1. Sketch of the algorithm: take the cv-decomposition ([conv.qual]/1) of T; each cvj can be augmented. If T is a reference, we can augment the referee type's cv-qualification.
Now add const volatile to all these places. Call the resulting type CT. Try static_casting the expression to CT instead. If that works, our cast chain is const_cast<T>(static_cast<CT>(e)).
If this doesn't work, there very probably is no conversion using static_cast followed by const_cast (I haven't delved into the deep corners of overload resolution (well I have, but not for this question)). But we could use brute force to repeatedly remove const/volatiles and check each type if we really wanted. So in theory, there is no ambiguity or underspecification; if there is some cast chain, it can be determined. In practice, the algorithm can be made very simple, because the "most cv-qualified" type we can construct from T is (assuredly) sufficient.
I've heard that the static_cast function should be preferred to C-style or simple function-style casting. Is this true? Why?
The main reason is that classic C casts make no distinction between what we call static_cast<>(), reinterpret_cast<>(), const_cast<>(), and dynamic_cast<>(). These four things are completely different.
A static_cast<>() is usually safe. There is a valid conversion in the language, or an appropriate constructor that makes it possible. The only time it's a bit risky is when you cast down to an inherited class; you must make sure that the object is actually the descendant that you claim it is, by means external to the language (like a flag in the object). A dynamic_cast<>() is safe as long as the result is checked (pointer) or a possible exception is taken into account (reference).
A reinterpret_cast<>() (or a const_cast<>()) on the other hand is always dangerous. You tell the compiler: "trust me: I know this doesn't look like a foo (this looks as if it isn't mutable), but it is".
The first problem is that it's almost impossible to tell which one will occur in a C-style cast without looking at large and disperse pieces of code and knowing all the rules.
Let's assume these:
class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
Now, these two are compiled the same way:
CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked
pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
// Safe; as long as we checked
// but harder to read
However, let's see this almost identical code:
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert
pOther = (CMyOtherStuff*)(pSomething); // No compiler error.
// Same as reinterpret_cast<>
// and it's wrong!!!
As you can see, there is no easy way to distinguish between the two situations without knowing a lot about all the classes involved.
The second problem is that the C-style casts are too hard to locate. In complex expressions it can be very hard to see C-style casts. It is virtually impossible to write an automated tool that needs to locate C-style casts (for example a search tool) without a full blown C++ compiler front-end. On the other hand, it's easy to search for "static_cast<" or "reinterpret_cast<".
pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
// No compiler error.
// but the presence of a reinterpret_cast<> is
// like a Siren with Red Flashing Lights in your code.
// The mere typing of it should cause you to feel VERY uncomfortable.
That means that, not only are C-style casts more dangerous, but it's a lot harder to find them all to make sure that they are correct.
One pragmatic tip: you can search easily for the static_cast keyword in your source code if you plan to tidy up the project.
In short:
static_cast<>() gives you a compile time checking ability, C-Style
cast doesn't.
static_cast<>() can be spotted easily
anywhere inside a C++ source code; in contrast, C_Style cast is harder to spot.
Intentions are conveyed much better using C++ casts.
More Explanation:
The static cast performs conversions between compatible types. It
is similar to the C-style cast, but is more restrictive. For example,
the C-style cast would allow an integer pointer to point to a char.
char c = 10; // 1 byte
int *p = (int*)&c; // 4 bytes
Since this results in a 4-byte pointer pointing to 1 byte of allocated
memory, writing to this pointer will either cause a run-time error or
will overwrite some adjacent memory.
*p = 5; // run-time error: stack corruption
In contrast to the C-style cast, the static cast will allow the
compiler to check that the pointer and pointee data types are
compatible, which allows the programmer to catch this incorrect
pointer assignment during compilation.
int *q = static_cast<int*>(&c); // compile-time error
Read more on:
What is the difference between static_cast<> and C style casting
and
Regular cast vs. static_cast vs. dynamic_cast
The question is bigger than just using whether static_cast<> or C-style casting because there are different things that happen when using C-style casts. The C++ casting operators are intended to make those different operations more explicit.
On the surface static_cast<> and C-style casts appear to be the same thing, for example when casting one value to another:
int i;
double d = (double)i; //C-style cast
double d2 = static_cast<double>( i ); //C++ cast
Both of those cast the integer value to a double. However when working with pointers things get more complicated. Some examples:
class A {};
class B : public A {};
A* a = new B;
B* b = (B*)a; //(1) what is this supposed to do?
char* c = (char*)new int( 5 ); //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error
In this example (1) may be OK because the object pointed to by A is really an instance of B. But what if you don't know at that point in code what a actually points to?
(2) may be perfectly legal (you only want to look at one byte of the integer), but it could also be a mistake in which case an error would be nice, like (3).
The C++ casting operators are intended to expose these issues in the code by providing compile-time or run-time errors when possible.
So, for strict "value casting" you can use static_cast<>. If you want run-time polymorphic casting of pointers use dynamic_cast<>. If you really want to forget about types, you can use reintrepret_cast<>. And to just throw const out the window there is const_cast<>.
They just make the code more explicit so that it looks like you know what you were doing.
static_cast means that you can't accidentally const_cast or reinterpret_cast, which is a good thing.
Allows casts to be found easily in
your code using grep or similar
tools.
Makes it explicit what kind
of cast you are doing, and engaging
the compiler's help in enforcing it.
If you only want to cast away
const-ness, then you can use
const_cast, which will not allow you
to do other types of conversions.
Casts are inherently ugly -- you as
a programmer are overruling how the
compiler would ordinarily treat your
code. You are saying to the
compiler, "I know better than you."
That being the case, it makes sense
that performing a cast should be a
moderately painful thing to do, and
that they should stick out in your
code, since they are a likely source
of problems.
See Effective C++ Introduction
It's about how much type-safety you want to impose.
When you write (bar) foo (which is equivalent to reinterpret_cast<bar> foo if you haven't provided a type conversion operator) you are telling the compiler to ignore type safety, and just do as it's told.
When you write static_cast<bar> foo you are asking the compiler to at least check that the type conversion makes sense and, for integral types, to insert some conversion code.
EDIT 2014-02-26
I wrote this answer more than 5 years ago, and I got it wrong. (See comments.) But it still gets upvotes!
C Style casts are easy to miss in a block of code. C++ style casts are not only better practice; they offer a much greater degree of flexibility.
reinterpret_cast allows integral to pointer type conversions, however can be unsafe if misused.
static_cast offers good conversion for numeric types e.g. from as enums to ints or ints to floats or any data types you are confident of type. It does not perform any run time checks.
dynamic_cast on the other hand will perform these checks flagging any ambiguous assignments or conversions. It only works on pointers and references and incurs an overhead.
There are a couple of others but these are the main ones you will come across.
static_cast, aside from manipulating pointers to classes, can also be used to perform conversions explicitly defined in classes, as well as to perform standard conversions between fundamental types:
double d = 3.14159265;
int i = static_cast<int>(d);