BCRYPT_ALG_HANDLE hAlg = nullptr;
DWORD HashObjectSize = 0;
ULONG CopyByte = NULL;
status = BCryptGetProperty
(
hAlg,
BCRYPT_OBJECT_LENGTH,
(PUCHAR)&HashObjectSize, //unsigned long =?= unsigned char*
sizeof(PUCHAR),
&CopyByte,
NULL
);
This code works without errors, but if i change the c-style cast to static_cast I get the error
Invalid conversion
DWORD is a unsigned long
PUCHAR is a unsigned char*
Why i can convert this variable with c-style cast, but can't with static_cast(PUCHAR)&HashObjectSize
static_cast can't cast from an integer to a pointer, and vice versa. Or between two unrelated types.
unsigned long* and unsigned char* are unrelated pointer types, so you can't static_cast between them, you need to use reinterpret_cast instead, eg:
reinterpret_cast<PUCHAR>(&HashObjectSize)
A C-style cast checks several different types of casts until one of them can be used. It will check reinterpret_cast if static_cast can't be used:
( new-type ) expression (1)
...
When the C-style cast expression is encountered, the compiler attempts to interpret it as the following cast expressions, in this order:
a) const_cast<new-type>(expression);
b) static_cast<new-type>(expression), with extensions: pointer or reference to a derived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class is inaccessible (that is, this cast ignores the private inheritance specifier). Same applies to casting pointer to member to pointer to member of unambiguous non-virtual base;
c) static_cast (with extensions) followed by const_cast;
d) reinterpret_cast<new-type>(expression);
e) reinterpret_cast followed by const_cast.
The first choice that satisfies the requirements of the respective cast operator is selected, even if it cannot be compiled (see example). If the cast can be interpreted in more than one way as static_cast followed by a const_cast, it cannot be compiled.
In addition, C-style cast notation is allowed to cast from, to, and between pointers to incomplete class type. If both expression and new-type are pointers to incomplete class types, it's unspecified whether static_cast or reinterpret_cast gets selected.
Related
I know that reinterpret_cast is primarily used going to or from a char*.
But I was surprised to find that static_cast could do the same with a void*. For example:
auto foo "hello world"s;
auto temp = static_cast<void*>(&foo);
auto bar = static_cast<string*>(temp);
What do we gain from using reinterpret_cast and char* over static_cast and void*? Is it something to do with the strict aliasing problem?
Generally speaking, static_cast will do cast any two types if one of them can be cast to the other implicitly. That includes arithmetic casts, down-casts, up-casts and cast to and from void*.
That is, if this cast is valid:
void foo(A a);
B b;
foo(b);
Then the both static_cast<B>(a) and static_cast<A>(b) will also be valid.
Since any pointer can be cast implicitly to void*, thus your peculiar behavior.
reinterpret_cast do cast by reinterpreting the bit-pattern of the values. That, as you said in the question, is usually done to convert between unrelated pointer types.
Yes, you can convert between unrelated pointer types through void*, by using two static_cast:
B *b;
A *a1 = static_cast<A*>(b); //compiler error
A *a2 = static_cast<A*>(static_cast<void*>(b)); //it works (evil laugh)!
But that is bending the rules. Just use reinterpret_cast if you really need this.
Your question really has 2 parts:
Should I use static_cast or reinterpret_cast to work with a pointer to the underlying bit pattern of an object without concern for the object type?
If I should use reinterpret_cast is a void* or a char* preferable to address this underlying bit pattern?
static_cast: Converts between types using a combination of implicit and user-defined conversions
In 5.2.9[expr.static.cast]13 the standard, in fact, gives the example:
T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
It leverages the implicit cast:
A prvalue pointer to any (optionally cv-qualified) object type T can be converted to a prvalue pointer to (identically cv-qualified) void. The resulting pointer represents the same location in memory as the original pointer value. If the original pointer is a null pointer value, the result is a null pointer value of the destination type.*
There is however no implicit cast from a pointer of type T to a char*. So the only way to accomplish that cast is with a reinterpret_cast.
reinterpret_cast: Converts between types by reinterpreting the underlying bit pattern
So in answer to part 1 of your question when you cast to a void* or a char* you are looking to work with the underlying bit pattern, reinterpret_cast should be used because it's use denotes to the reader a conversion to/from the underlying bit pattern.
Next let's compare void* to char*. The decision between these two may be a bit more application dependent. If you are going to use a standard library function with your underlying bit pattern just use the type that function accepts:
void* is used in the mem functions provided in the cstring library
read and write use char* as inputs
It's notable that C++ specific libraries prefer char* for pointing to memory.
Holding onto memory as a void* seems to have been preserved for compatibility reasons as pointer out here. So if a cstring library function won't be used on your underlying bit patern, use the C++ specific libraries behavior to answer part 2 of your question: Prefer char* to void*.
Why do you need a C-style cast for the following?
int* ptr = static_cast<int*>(0xff); // error: invalid static_cast from type 'int'
// to type 'int*'
int* ptr = (int*) 0xff; // ok.
static_cast can only cast between two related types. An integer is not related to a pointer and vice versa, so you need to use reinterpret_cast instead, which tells the compiler to reinterpret the bits of the integer as if they were a pointer (and vice versa):
int* ptr = reinterpret_cast<int*>(0xff);
Read the following for more details:
Type conversions
You need a C-style cast or directly the reinterpret_cast it stands for when casting an integer to a pointer, because the standard says so for unrelated types.
The standard mandates those casts there, because
you are doing something dangerous there.
you are doing something very seldom useful.
you are doing something highly implementation-dependent.
most times, that is simply a programming-error.
When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?
Regular cast vs. static_cast vs. dynamic_cast
Being late to the party I found that the following works only using static casts:
int* ptr1 = static_cast<int*>(static_cast<void*>(static_cast<unsigned char*>(nullptr) + 0xff));
This way you don't translate the constant directly to a pointer, instead you add it as a bytewise offset to the nullptr.
The C++ standards mentions that reinterpret_cast is implementation defined, and doesn't give any guarantees except that casting back (using reinterpret_cast) to original type will result in original value passed to first.
C-style casting of at least some types behaves much the same way - casting back and forth results with the same value - Currently I am working with enumerations and ints, but there are some other examples as well.
While C++ standard gives those definitions for both cast-styles, does it also give the same guarantee for mixed casts? If library X returns from function int Y() some enum value, can use any of above casts, without worrying what cast was used to convert initial enum to int in Y's body? I don't have X's source code, so I cannot check (and it can change with next version anyway), and things like that are hardly mentioned in documentation.
I know that under most implementations in such cases both casts behave the same; my question is: what does C++ standard say about such cases - if anything at all.
C++ defines the semantic of the C cast syntax in terms of static_cast, const_cast and reinterpret_cast. So you get the same guaranteed for the same operation whatever syntax you use to achieve it.
reinterpret_cast can only be used for specific conversions:
Pointer to (sufficiently large) integer, and the reverse
Function pointer to function pointer
Object pointer to object pointer
Pointer-to-member to pointer-to-member
lvalue expression to reference
plus (conditionally) function pointer to object pointer and the reverse. In most cases, the converted value is unspecified, but there is a guarantee that a conversion followed by its reverse will yield the original value.
In particular, you can't use reinterpret_cast to convert between integer an enumeration types; the conversion must be done using static_cast (or implicitly, when converting an unscoped enumeration to an integer type), which is well defined for sufficiently large integer types. The only possible problem is if the library did something completely insane such as return reinterpret_cast<int&>(some_enum);
A C-style cast will perform either a static_cast or a reinterpret_cast, followed by a const_cast, as necessary; so any conversion that's well-defined by static_cast is also well-defined by a C-style cast.
No, reinterpret_cast is not equivalent to a C style cast. C style casts allow casting away const-volatile (so it includes the functionality of const_cast) not allowed in reinterpret_cast. If static_cast is allowed between the source and destination types, it will perform a static_cast which has different semantics than reinterpret_cast. It the conversion is not allowed, it will fallback to reinterpret_cast. Finally there is a corner case where the C cast cannot be represented in terms of any of the other casts: it ignores access specifiers.
Some examples that illustrate differences:
class b0 { int a; };
class b1 { int b; };
class b2 { int c; };
class d : public b0, public b1, b2 {};
int main() {
d x;
assert( static_cast<b1*>(&x) == (b1*)&x );
assert( reinterpret_cast<b1*>(&x) != (b1*)&x ); // Different value
assert( reinterpret_cast<b2*>(&x) != (b2*)&x ); // Different value,
// cannot be done with static_cast
const d *p = &x;
// reinterpret_cast<b0*>(p); // Error cannot cast const away
(b0*)p; // C style can
}
I want to reinterpret an unsigned long (actually, a DWORD) as a signed long. I tried:
DWORD x;
long y = reinterpret_cast<signed long>(x);
However, VC++2010 intellisense tells me "Invalid type conversion". Why? How do I fix it?
You don't need reinterpret_cast to convert unsigned type into a signed one, static_cast will do.
try static_cast instead. VC generates an error if you try an excessively permissive cast (like using reinterpret_cast when static_cast or const_cast will suffice).
There are 5 types of casts in C++, each of which allows you to do more (grants more permissions). The least permissive casts are const casts (const_cast<int>(<const int>)) which allow you to change the const modifier. There are static casts (static_cast<int>)(<short>)) which allow you to perform type safe coersions (cast base to derived, for example).There are dynamic casts (dynamic_cast<derived_type>(base_type) that allow you to cast from one type to another if there is a legal conversion between the two (and that return null if there is no conversion). Finally, there are casts that allow conversion between unrelated types - reinterpret_cast reinterpret_cast<int>(<void *>) and C style cast (int)<void *>.
I don't have a good way of describing these different types of casts, so I describe them as "more permissive" because each of them allows you to do more.
VC warns you if you are using a reinterpret cast when one of the other cast types would be more appropriate to achieve your goal. C style casts don't have a similar warning for backwards compatibility.
In C++ for any data type I can do the following:
Type* typedPointer = obtain();
void* voidPointer = typedPointer;
which cast is performed when I assign Type* to void*? Is this the same as
Type* typedPointer = obtain();
void* voidPointer = reinterpret_cast<void*>( typedPointer );
or is it some other cast?
It is a standard pointer conversion. Since it is a standard conversion, it doesn't require any explicit cast.
If you want to reproduce the behavior of that conversion with an explicit cast, it would be static_cast, not reinterpret_cast.
Be definition of static_cast given in 5.2.9/2, static_cast can perform all conversions that can be performed implicitly.
It is not a cast, it is implicit conversion. Casts are explicit by definition. It is no more a cast than:
char c = 'a';
int i = c;
is.
From Type* to void* implicit conversion is available. You can use static_cast to clarify the intention of the code. For the reverse you require reinterpret_cast
EDIT: As per comment for the reverse also static_cast can be used. Tried a sample piece of code and it indeed compiles. Didn't knew that and always used reinterpret_cast to cast from a void*.
It is the same cast. Any pointer can be cast to a void-pointer.