I am reading a C++ book and have a problem with the static casting. Here is a function:
void fun(int*pi)
{
void *pv = pi
int *pi2 = static_cast<int*>(pv); //explicit conversion back to int*
double *pd3 = static_cast<double*>(pv); //unsafe
}
The last statement:
double*pd3 = static_cast<double*>(pv);
is considered as unsafe. I don't get why it is considered unsafe.
The cast reinterprets the bits of the pointed to int, plus possibly bits of some following memory (if there is!), as a double value.
A double is (1) typically larger than an int, and (2) has some internal structure.
Point (1) means that any use of the dereferenced result pointer, may access memory that just isn't accessible, beyond the int.
Point (2) means that the arbitrary bitpattern, may be invalid as a double bitpattern, and may cause a hardware exception a.k.a. a "trap" when it's used. From a C++ point of view that's Undefined Behavior. From a practical programming point of view it's typically a "crash".
In contrast, accessing the bits of a double as an int is usually in-practice safe, even though it's formally UB, because (1) an int is typically smaller or equal in size to double, and (2) an int usually does not have any invalid bit patterns. However, depending on the compiler options the compiler may not be happy about doing that directly.
Above I forgot to mention alignment, as Loki Astari pointed out in a comment. And that's a reason (3) for unsafety. As an example, with some given implementation an int may be allowed to have an address that is a multiple of 4, while a double may be required to reside at an address that is a multiple of 8. Then the dereferenced pointer may access a double at an address such that isn't a multiple of 8, causing a trap (more formally, UB where anything can happen).
Because the size of a double pointer is not the same as an int pointer, and if you try to use it, you might get a segmentation fault. They are not necessarily compatible types.
You can try casting the value pointed by pi2.
void fun(int*pi)
{
void *pv = pi;
int *pi2 = static_cast<int*>(pv);
double d = static_cast<double>(*pi2);
std::cout << d; // 42
}
int main()
{
int i = 42;
fun(&i);
}
Related
The from_base function returns the memory address from the base to a selected
value in a program. I want to retrieve this value and return it in a function, however, I am getting a warning that says integer to pointer cast pessimism optimization opportunities.
DWORD chat::client() {
return *reinterpret_cast<DWORD*>(core::from_base(offsets::chat::client));
}
I am also getting this warning when casting a function from the program:
auto og_print = reinterpret_cast<chat::fn_print_chat>(core::from_base(offsets::chat::print));
I don't understand why I am getting a warning from clang-tidy about integer to pointer cast pessimism optimization opportunities
performance-no-int-to-ptr
I looked it up, but I can't figure it out. The code works, and gets the correct value. I am just concerned about the warning.
If a program performs a computation like:
char x[10],y[10];
int test(ptrdiff_t i)
{
int *p = x+i;
*p = 1;
y[1] = 2;
return *p;
}
a compiler would be reasonably entitled to assume that because p was formed via pointer arithmetic using x, it could not possible equal y+1, and thus the function would always return 1. If, however, the code had been written as:
char x[10],y[10];
int test(ptrdiff_t i)
{
int *p = (char*)((uintptr_t)x + i);
*p = 1;
y[1] = 2;
return *p;
}
then such an assumption would be far less reasonable, since unsigned numerical semantics would define the behavior of uintptr_t z = (uintptr_t)(y+1)-(uintptr_t)x as yielding a value such that x+z would equal (uintptr_t)(y+1).
I find the apparent caution clang exhibits here a bit surprising, given that clang is prone to assume that, given some pointer char*p, it's not possible for p to equal y if (uintptr_t)p to equal (uintptr_t)(x+10) and yet for p to equal y. The Standard doesn't forbid such an assumption, but then again it also wouldn't forbid an assumption that code will never use the result of any integer-to-pointer conversion for any purpose other than comparisons with other pointers. Implementations that support type uintptr_t should of course offer stronger guarantees about round-tripped pointers which than merely saying they may be compared for equality with the originals, but the Standard doesn't require such treatment.
I know this code would cause undefined behaviour due to breaking the strict aliasing rule,
as we are point to the same memory location with a type int and float and dereferencing it, code could break after compiler optimizations take place:
int main(){
int a = 5;
float f = *reinterpret_cast<float*>(&a);
return (int) f;
}
But how about this snippet?
#include <iostream>
int main(){
intptr_t p = 1234; // let's assume this is a valid address in memory.
float f = *reinterpret_cast<float*>(p);
return (int) f;
}
In the above, if we assume p is a valid memory address (will not cause a segfault) will it still have UB and break the strict aliasing rule? there is no other code pointing to that chunk of memory.
Edit
My second example can be written like this using bit_cast:
intptr_t p = 1234; // let's assume this is a valid address in memory.
float f = *std::bit_cast<float*>(p);
Yes, it will still break the strict aliasing rule, as you will be trying to dereference a pointer to float, but float object never lived at this address.
Luckily, in C++ 20 you can use std::bit_cast for this purpose. Pre-C++20 you can just cast :), as even though this is UB, there is no sane compiler which would produce the results which would be different from the ones you are expecting, since this technique is omni-present everywhere.
Consider the following code:
int square(volatile int *p)
{
return *p * *p;
}
Now, the volatile keyword indicates that the value in a
memory location can be altered in ways unknown to the compiler or have
other unknown side effects (e.g. modification via a signal interrupt,
hardware register, or memory mapped I/O) even though nothing in the
program code modifies the contents.
So what exactly happens when we declare a pointer as volatile?
Will the above mentioned code always work, or is it any different from this:
int square(volatile int *p)
{
int a = *p;
int b = *p
return a*b;
}
Can we end up multiplying different numbers, as pointers are volatile?
Or is there better way to do so?
Can a pointer be volatile?
Absolutely; any type, excluding function and references, may be volatile-qualified.
Note that a volatile pointer is declared T *volatile, not volatile T*, which instead declares a pointer-to-volatile.
A volatile pointer means that the pointer value, that is its address and not the value pointed to by, may have side-effects that are not visible to the compiler when it's accessed; therefore, optimizations deriving from the "as-if rule" may not be taken into account for those accesses.
int square(volatile int *p) { return *p * *p; }
The compiler cannot assume that reading *p fetches the same value, so caching its value in a variable is not allowed. As you say, the result may vary and not be the square of *p.
Concrete example: let's say you have two arrays of ints
int a1 [] = { 1, 2, 3, 4, 5 };
int a2 [] = { 5453, -231, -454123, 7565, -11111 };
and a pointer to one of them
int * /*volatile*/ p = a1;
with some operation on the pointed elements
for (int i = 0; i < sizeof(a1)/sizeof(a1[0]); ++i)
*(p + i) *= 2;
here p has to be read each iteration if you make it volatile because, perhaps, it may actually point to a2 due to external events.
Yes, you can of course have a volatile pointer.
Volatile means none more and none less than that every access on the volatile object (of whatever type) is treated as a visible side-effect, and is therefore exempted from optimization (in particular, this means that accesses may not be reordered or collapsed or optimized out alltogether). That's true for reading or writing a value, for calling member functions, and of course for dereferencing, too.
Note that when the previous paragraph says "reordering", a single thread of execution is assumed. Volatile is no substitute for atomic operations or mutexes/locks.
In more simple words, volatile generally translates to roughly "Don't optimize, just do exactly as I say".
In the context of a pointer, refer to the exemplary usage pattern given by Chris Lattner's well-known "What every programmer needs to know about Undefined Behavior" article (yes, that article is about C, not C++, but the same applies):
If you're using an LLVM-based compiler, you can dereference a "volatile" null pointer to get a crash if that's what you're looking for, since volatile loads and stores are generally not touched by the optimizer.
Yes. int * volatile.
In C++, keywords according to type/pointer/reference go after the token, like int * const is constant pointer to integer, int const * is pointer to constant integer, int const * const is constant pointer to constant integer e.t.c. You can write keyword before the type only if it's for the first token: const int x is equal to int const x.
The volatile keyword is a hint for the compiler (7.1.6.1/7):
Note:
volatile
is a hint to the implementation to avoid aggressive optimization involving the object
because the value of the object might be changed by means undetectable by an implementation. Furthermore,
for some implementations,
volatile
might indicate that special hardware instructions are required to access
the object. See
1.9
for detailed semantics. In general, the semantics of
volatile
are intended to be the
same in C
++
as they are in C.
— end note
]
What does it mean? Well, take a look at this code:
bool condition = false;
while(!condition)
{
...
}
by default, the compiler will easilly optimize the condition out (it doesn't change, so there is no need to check it at every iteration). If you, however, declare the condition as volatile, the optimization will not be made.
So of course you can have a volatile pointer, and it is possible to write code that will crash because of it, but the fact that a variable is volative doesn't mean that it is necessarily going to be changed due to some external interference.
Yes, a pointer can be volatile if the variable that it points to can change unexpectedly even though how this might happen is not evident from the code.
An example is an object that can be modified by something that is external to the controlling thread and that the compiler should not optimize.
The most likely place to use the volatile specifier is in low-level code that deals directly with the hardware and where unexpected changes might occur.
You may be end up multiplying different numbers because it's volatile and could be changed unexpectedly. So, you can try something like this:
int square(volatile int *p)
{
int a = *p;
return a*a;
}
int square(volatile int *p)
{
int a = *p;
int b = *p
return a*b;
}
Since it is possible for the value of *ptr to change unexpectedly, it is possible for a and b to be different. Consequently, this code could return a number that is not a square! The correct way to code this is:
long square(volatile int *p)
{
int a;
a = *p;
return a * a;
}
Running this code returns what I assume to be the integer value of realPtr's address.
I'm still new to C++ and I was wondering - is it possible to convert from one data type pointer to another and the pointer variable whose value is assigned will still print out the right value (i.e. *integerPtr prints out 2)?
Code snippet
double real = 2.0;
double *realPtr = ℜ
int *integerPtr;
integerPtr = ((int*)&realPtr);
cout << *integerPtr << endl;
Output
1606416424
Thanks!
There are 3 totally different types that you are dealing with here:
Pointers point to any location in memory. Every pointers are basically the same type, but they are treated as different types depending on what you declare them to point to.
int, and double are types that represent integer and real numeric value; An integer and a double representing the same numerical value (e.g. 2) will not have the same binary content as stipulated by the relevant standard defining how integers and floating point numerics are stored in memory.
Since every pointers are essentially the same type, you may cast a kind of pointer to any other kind. Let's say you have your own Foo class that has nothing to do with representing numerical value. You may still do this:
int* p_int = 2;
Foo* p_foo = (Foo*) p_int;
This is legal, but this will most probably lead to an error, unless the memory representation of a Foo object is akin to that of an int.
If you want to cast an int to a double, you must cast the data, casting the pointer won't do anything. That's why there are several cast with different names in C++11, and it is considered good practice to use them since by doing so you express explicitly what you want to be done. In your case, you may want one of two different things
Reinterpret_cast
Casting a pointer to an int to a pointer to a double, which means essentially doing nothing except telling the compiler that it can safely assume that the data pointed to can be considered as a double. The compiler will assume so, and it is your responsibility to assure that it is the case. This type of cast is considered the most dangerous since as we all know, programmers can't be trusted. It is called a reinterpret_cast:
int* p_int = 2;
Foo* p_foo = reinterpret_cast<int>(p_int);
Same code as above, but we express the danger in the scary "reinterpret_cast". p_int and p_foo have the same value, we did nothing except expressing the fact that we now consider the address of our integer as an address to a foo.
Static_cast
If you want a real cast, you have to operate on the data, not on the pointer. Casting a type of data to another by whatever means the compilers know of is called static_cast. This is probably what you want to do here:
int i = 2;
p_int = &i;
double d = static_cast<double>(i);
p_double = &d; //p_int and p_double have different values since they point to different objects.
The compiler will look for a conversion function from int to double, and yell at you if it doesn't find any.
Of course, there is nothing wrong with doing the exact same thing by using only pointers, although it makes the code slightly less readable (you should be wary of using pointers at all, and do it for a good reason):
int* p_i = 2;
int* p_d = static_cast<double>(*p_i) // p_d is a pointer to a double initialized to the value obtained after converting the int pointed to by p_i
The internal representation of float/dobule and integer data types are different. In a 32 bit PC Integer will take 4 bytes while a double take 8 bytes.
Also there is a serious bug in your code.
double real = 2.0;
double *realPtr = ℜ
int *integerPtr;
integerPtr = ((int*)&realPtr);
cout << *integerPtr << endl;
In the above code see the bold lines. There you declared a pointer to an integer called "integerPtr". But the actual value stored address of a pointer to a double. ie &realPtr is double ** (Pointer to a pointer which holds a double type value). And then you are trying to print the value using *integerPtr.
So I changed your code as follows and it gives a value of 0.
double real = 2.0;
double *realPtr = ℜ
int *integerPtr;
integerPtr = ((int*)realPtr);
std::cout << *integerPtr << std::endl;
How can I cast a void pointer to a double, retaining the exact binary stored in the void pointer? I thought this could be done with reinterpret_cast<double>(voidp), but g++ doesn't let me. I know you can cast void pointers to integers, so I tried reinterpret_cast<double>(reinterpret_cast<long>(voidp)), but apparently that's also invalid. sizeof(double) and sizeof(void*) are both 8, so it can't be a size thing. Is there anything I can do to accomplish this?
EDIT: The double in this case is not pointed to by the void pointer, but /is/ the void pointer - the pointer itself contains the data I want, it does not point to the data I want.
Direct memory reinterpretation, by definition, means working with lvalues. The most straightforward approach would be to do it though a cast to reference type
double d = reinterpret_cast<double &>(voidp);
You can also do it through a pointer cast, as other answers suggested, although it "overloads" the procedure with a number of completely unnecessary operator applications. Both approaches are equivalent, since by definition reinterpret_cast to reference type reinterpret_cast<T &>(v) is equivalent to the pointer version *reinterpret_cast<T *>(&v).
However, the above approaches suffer from type-punning issues. Formally, doing this is simply illegal. You are not allowed to read void * objects as double objects in C++. Direct memory reinterpretation exists in C++ for re-interpreting objects as arrays of chars, not for arbitrary type-punning like the above. Even if we ignore the formal issue and stick to purely "practical" considerations, trying to directly reinterpret a void * value as double value might produce completely unexpected and meaningless results in a compiler that follows strict-aliasing semantics when performing optimizations.
A better idea might be to memcpy the void * object to the double object
double d;
assert(sizeof d == sizeof voidp); // <- a static assert would be even better
memcpy(&d, &voidp, sizeof d);
Alternatively, in C you are now allowed to use unions for that purpose. I'm not sure the formal permission made into C++ yet, but it will typically work in practice.
The memcpy() method should be your preferred method of type punning:
double d = 100;
void *x;
std::memcpy(&x, &d, sizeof x);
std::cout << x << '\n';
double d2;
std::memcpy(&d2, &x, sizeof d2);
std::cout << d2 << '\n';
You might think this would be slower than a cast, but in fact compilers are smart enough to recognize what's going on here and generate optimal code: http://blog.regehr.org/archives/959
In addition, this method cannot result in undefined behavior due to aliasing violations as can happen with casts or union methods.
You can write a bit_cast operator to make this more convienent and more safe:
http://pastebin.com/n4yDjBde
template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
static_assert(sizeof(Dest)==sizeof(Source), "size of destination and source objects must be equal");
static_assert(std::is_trivially_copyable<Dest>::value, "destination type must be trivially copyable.");
static_assert(std::is_trivially_copyable<Source>::value, "source type must be trivially copyable");
Dest dest;
std::memcpy(&dest, &source, sizeof(dest));
return dest;
}
Example usage:
void *p = ...;
double d = bit_cast<double>(p);
If you do type punning you ought to be aware of trap values for the involved types and your compiler's behavior with traps and unspecified values.
This is not recommended at all, but if you have to, use:
*reinterpret_cast<double*>(&voidp)
void* some_void_data = NULL;
double* as_double = static_cast<double*>(some_void_data);
double as_double_copy = *as_double;
double as_double_copy_one_line = *static_cast<double*>(some_void_data);
Obviously you'd want to apply the cast to a non-null pointer in real usage. static_cast can only be used to convert from one pointer type to another pointer type. If you want a copy of the pointer you're expected to perform the copy yourself by dereferencing the pointer returned by the cast.
This is a good resource on casting.