I have the followig code and I want to know why I have the following output:
#include <iostream>
int main() {
double nValue = 5;
void *pVoid = &nValue;
short *pInt = static_cast<short*>(pVoid);
std::cout << *pInt << std::endl;
return 0;
}
And it outputs me '0'. I want to know why is this happening. Thank you!
You have UB (Undefined Behaviour), as you're violating pointer aliasing rules. This means anything can happen.
For example, the compiler has all rights to expect a short* will never refer to a double object, so it can pretty much interpret *pInt however it wants.
Or it's possible that the compiler interprets the code literally, and it just so happens that on your platform, the binary representation of 5.0 starts with two (or sizeof(short)) bytes of zeroes.
You are casting memory block with double data to short. Since you store a small value in that block it is not stored in first bits. Thus first bits are zero. But it rely on internal double representation and short size, so it is not guaranteed to be the same on different platforms
You're trying to interpret the contents of a double as a short. This invokes undefined behavior - your program is free to do anything.
pVoid points to a bit pattern that represents a double. The type information is lost for the compiler once you use a void*. When casting the void* to short*, you claim that that the bit pattern pointed to is a short, which it isn't. The representation of a short and a double in memory are completely different. When you dereference pInt, the memory at that location happens to be 0. The compiler no longer knows at this point that the value's type is really double, so no implicit conversion is possible, if that's what you were expecting.
Just for fun, most probably the double representation of 5 on your machine is this
*double = (5)
0000000000000000000000000000000000000000000000000000000000000101
^^^^^^^^^^^^^^^^
*short = (0)
This should show you why this is happeneing
int main() {
double nValue = 5;
short nValue_short = 5;
std::bitset<sizeof(double)*8> bit_double(nValue);
std::bitset<sizeof(short)*8> bit_short(nValue_short);
std::cout << bit_double << std::endl;
std::cout << bit_short << std::endl;
return 0;
}
Related
I know. I know. This question has been answered before, but I have a slightly different and a bit more specific question.
My goal is, as the title suggest, to cout the 32 bits sequence of a float.
And the solution provided in the previous questions is to use a union.
union ufloat{
float f;
uint32_t u;
};
This is all good and well. And I have managed to print the bits of a floating number.
union ufloat uf;
uf.f = numeric_limits<float>::max();
cout << bitset<32>(uf.f) << "\n"; // This give me 0x00000000, which is wrong.
cout << bitset<32>(uf.u) << "\n"; // This give me the correct bit sequence.
My question is why does bitset<32>(uf.f) doesn't work, but bitset<32>(uf.u) does?
The green-ticked anwser of this question
Obtaining bit representation of a float in C says something about "type-punning", and I presume it's got something to do with that. But I am not sure how exactly.
Can someone please clearify? Thanks
The constructor of std::bitset you are calling is:
constexpr bitset( unsigned long long val ) noexcept;
When you do bitset<32>(uf.f), you are converting a float to an unsigned long long value. For numeric_limits<float>::max(), that's undefined behavior because it's outside the range of the destination type, and in your case it happened to produce zero.
When you do bitset<32>(uf.u), you are again relying on undefined behavior, and in this case it happens to do what you want: convert a uint32_t that contains the bits of a float to an unsigned long long value.
In C++, what you should do instead is use memcpy:
uint32_t u;
std::memcpy(&u, &uf.f, sizeof(u));
std::cout << std::bitset<32>(u) << "\n";
This question is tagged C++, but the linked one is about C.
Those are different languages, with different rules. In particular, as mentioned in the comments by Yksisarvinen:
Type punning is a way to read bytes of memory as if they were different type than they really are. This is possible to do through union in C, but in C++ reading anything but the last written to member of union is Undefined Behaviour.
Since C++20, we can use std::bit_cast.
auto f{ std::numeric_limits<float>::max() }; // -> 3.40282e+38
auto u{ std::bit_cast<unsigned>(f) }; // -> 7f7fffff
See e.g. https://godbolt.org/z/d9T3G6qGx.
I have a return value from a library which is a void pointer. I know that it points to a short int; I try to obtain the int value in the following way (replacing the function call with a simple assignment to a void *):
short n = 1;
void* s = &n;
int k = *(int*)s;
I try to cast a void pointer that points to an address in which there is a short and I try to cast the pointer to point to an int and when I do so the output becomes a rubbish value. While I understand why it's behaving like that I don't know if there's a solution to this.
If the problem you are dealing with truly deals with short and int, you can simply avoid the pointer and use:
short n = 1;
int k = n;
If the object types you are dealing with are different, then the solution will depend on what those types are.
Update, in response to OP's comment
In a comment, you said,
I have a function that returns a void pointer and I would need to cast the value accordingly.
If you know that the function returns a void* that truly points to a short object, then, your best bet is:
void* ptr = function_returning_ptr();
short* sptr = reinterpret_cast<short*>(ptr);
int k = *sptr;
The last line work since *sptr evaluates to a short and the conversion of a short to an int is a valid operation. On the other hand,
int k = *(int*)sptr;
does not work since conversion of short* to an int* is not a valid operation.
Your code is subject to undefined behavior, as it violates the so-called strict aliasing rules. Without going into too much detail and simplifying a bit, the rule states that you can not access an object of type X though a pointer to type Z unless types X and Z are related. There is a special exception for char pointer, but it doesn't apply here.
In your example, short and int are not related types, and as such, accessing one through pointer to another is not allowed.
The size of a short is only 16 bits the size of a int is 32 bits ( in most cases not always) this means that you are tricking the computer into thinking that your pointer to a short is actually pointing to an integer. This causes it to read more memory that it should and is reading garbage memory. If you cast s to a pointer to a short then deference it it will work.
short n = 1;
void* s = &n;
int k = *(short*)s;
Assuming you have 2 byte shorts and 4 byte ints, There's 3 problems with casting pointers in your method.
First off, the 4 byte int will necessarily pick up some garbage memory when using the short's pointer. If you're lucky the 2 bytes after short n will be 0.
Second, the 4 byte int may not be properly aligned. Basically, the memory address of a 4 byte int has to be a multiple of 4, or else you risk bus errors. Your 2 byte short is not guaranteed to be properly aligned.
Finally, you have a big-endian/little-endian dependency. You can't turn a big-endian short into a little-endian int by just tacking on some 0's at the end.
In the very fortunate circumstance that the bytes following the short are 0, AND the short is integer aligned, AND the system uses little-endian representation, then such a cast will probably work. It would be terrible, but it would (probably) work.
The proper solution is to use the original type and let the compiler cast. Instead of int k = *(int*)s;, you need to use int k = *(short *)s;
I get 2 errors when trying to compile this code:
#include <iostream>
using namespace std;
int main() {
int i;
char myCharArray[51] = "This string right here contains exactly 50 chars.";
double myDoubleArray[4] = {100, 101, 102, 103};
char *cp, *cbp;
double *dp, *dbp;
dp = &myDoubleArray[0];
dbp = myDoubleArray;
cp = &myCharArray[0];
cbp = myCharArray;
while ((cp-cbp) < sizeof(myCharArray)) {cp++; dp++; }
cout << "Without cast: " << (dp-dbp) << endl;
cout << " Cast 1: " << ((int *) dp-(int *) dbp) << endl;
cout << " Cast 2: " << ((int) dp-(int) dbp) << endl;
}
The errors I get are:
error: cast from ‘double*’ to ‘int’ loses precision [-fpermissive]
error: cast from ‘double*’ to ‘int’ loses precision [-fpermissive]
g++ won't let me compile the program. I'm asking what I could change to make it compile.
cast from ‘double*’ to ‘int’ loses precision
is as simple as it could be read: The number of bits to store in an int is less then the number of bits which are stored in a pointer on your platform. Normally it helps to make the int to an unsigned int, because on most platforms a pointer can be stored in an unsigned int type. A unsigned int has one more bit for the value because there is no need to decide between positive and negative. And pointers are always positive.
And even better is to use the types for such things to make your code more portable. Have a look for uintptr_t
Your "Without cast" line performs pointer subtraction, which yields the difference (in units of the size of the pointed-to type) between two pointers. If the two pointers point to elements of the same array, or just past the end of it, then the difference is the number of array elements between them. The result is of the signed integer type ptrdiff_t.
That's a perfectly sensible thing to do.
Your second line ("Cast 1:") converts the pointers (which are of type double*) to int* before the subtraction. That in effect pretends that the pointers are pointing to elements of an array of int, and determines the number of elements between the int objects to which they point. It's not at all clear why you'd want to do that.
Your third line ("Cast 2:") converts both pointer values to int before subtracting them. If int is not big enough to hold the converted pointer value, then the result may be nonsense. If it is, then on most systems it will probably yield the distinct between the two pointed-to objects in bytes. But I've worked on systems (Cray T90) where the byte offset of a pointer is stored in the high-order 3 bits of the pointer value. On such a system your code would probably yield the distance between the pointed-to objects in words. Or it might yield complete nonsense. In any case, the behavior is undefined.
The problem with the conversion from double* to int isn't just that it loses precision (which is what your compiler happened to complain about). It's that the result of the conversion doesn't necessarily mean anything.
The easiest, and probably the best, way to get your code to compile is to delete the second and third lines.
If you want a solution other than that, you'll have to explain what you're trying to do. Converting the pointer values to uintptr_t will probably avoid the error message, but it won't cause what you're doing to make sense.
I have such code:
double x = 100.1;
double y;
int *p;
p = (int *) &x;
y = *p;
cout << "y value is: " << y << endl;
I understand that it's wrong and we get 4 bytes instead of our 8 bytes. I also know floating numbers have some tricky representation at memory (but don't know how), but this script gives me such output:
y value is: 1.71799e+09
As I understand it's also value with floating point. By my pointer is int and I also expect int result. Why it's not? What I should read to understand?
By my pointer is int and I also expect int result. Why it's not?
Because y is a double, not an int. Now, if you mean to ask why doesn't y have an integral value, since it should be the result of the conversion of an int (which must* have an integral value) to double, take a look at the output of the following:
std::cout << "y value is: " << std::fixed << y << '\n';
The output you should see is:
y value is: 1717986918.000000
So, y does have an integral value, you simply printed it out using scientific notation. And if you wonder why y has this particular integral value, it's because that's the value *p had.
std::cout << "*p is: " << *p << '\n';
*p is: 1717986918
If you were to look at a memory dump of x with the value of 100.1, you would see:
66 66 66 66 66 06 59 40
And when you access this as an int, you get 66 66 66 66, which, converted to decimal, is 1717986918.
One other thing to note is that none of this is guaranteed by C++. In fact your program is not actually legal, because you're violating the aliasing rules when you access the double x through a pointer to int. Your program could be made legal and get the same results, but C++ doesn't specify the representation of floating point values, so the particular integral value could legally be different.
What I should read to understand?
Here's an article that plays with the representation of floats: http://ridiculousfish.com/blog/posts/float.html
C++ doesn't specify how floats are represented, but most C++ implementations use IEEE-754, so you might also take a look at that specification. Here's the wikipedia page to start you on that: https://en.wikipedia.org/wiki/IEEE_floating_point
To learn about C++'s aliasing rules you can find and read the spec. strict aliasing is covered in §3.10/10, IIRC. There are also plenty of questions and answers about aliasing here on SO.
1.71799e+09 is the floating point representation of the integer 1,717,99x,xxx.
By my pointer is int and I also expect int result. Why it's not?
Your pointer is int *, and you are getting an int result.
But that's not what you're displaying. You're displaying y which is a double.
1.71799e+09 is the double representation of the int you got.
When you do
y = *p;
The variable y takes the int pointed to by p, and then converts it to a double.
Suppose sizeof(double) is 8 and sizeof(int) is 4
Doing x = 100; you put the double value 100 in x on 8 bytes. Then when you do y = *p; you would only use 4 of the 8 bytes, as an int value, then convert that number to a double.
The binary format of a double and of an int are different. E.g. 100 as double is not represented the same way as 100 int (let alone the size difference, e.g. 8 vs 4).
See this link
double x = 100.1;
double y;
int *p;
p = (int *) &x;
// Set a pointer of type integer to point at a floating point. Better C++ style
// would be p = reinterpret_cast<int *>(&x);
// which explains more clearly what you are doing - reinterpreting the pointer as
// a different type.
y = *p;
// *p is an integer. So y is set to the value of *p, which is some crazy
// integer value formed from the interpretation of a double as integer.
cout << "y value is: " << y << endl;
See comments in the code above. You are making a pointer point to data of a different type, then wondering why the binary digits transformed don't represent what it originally represented...
(Technically, this code is in violation of the rules about aliasing - basically, you are using the same piece of memory for two different purposes, and the compiler is not obliged to "do the right thing" in this case - I suspect it does something of what you can expect in this particular case - if what you expect is that you get an integer value represented by the four first bytes of a double, that is).
If you want y to actually contain the integer representation of the number in x, you want:
y = (int)x;
There is no sensible way we can use a pointer to do this conversion.
You're triggering undefined behavoir when you run the following line:
p = (int *) &x;
Once you've triggered undefined behavoir the rest of your question is fairly pointless as reasoning about undefined behavoir doesn't make sense (although looking at the rest of your question, it may be that this bit of undefined behavoir doesn't affect what you're really asking. I'm not sure though.)
Read C++ pointers and data types documentation
http://www.cplusplus.com/doc/tutorial/pointers/
http://www.cplusplus.com/doc/tutorial/variables/
define a float variable a, convert a to float & and int &, what does this mean? After the converting , a is a reference of itself? And why the two result is different?
#include <iostream>
using namespace std;
int
main(void)
{
float a = 1.0;
cout << (float &)a <<endl;
cout << (int &)a << endl;
return 0;
}
thinkpad ~ # ./a.out
1
1065353216
cout << (float &)a <<endl;
cout << (int &)a << endl;
The first one treats the bits in a like it's a float. The second one treats the bits in a like it's an int. The bits for float 1.0 just happen to be the bits for integer 1065353216.
It's basically the equivalent of:
float a = 1.0;
int* b = (int*) &a;
cout << a << endl;
cout << *b << endl;
(int &) a casts a to a reference to an integer. In other words, an integer reference to a. (Which, as I said, treats the contents of a as an integer.)
Edit: I'm looking around now to see if this is valid. I suspect that it's not. It's depends on the type being less than or equal to the actual size.
It means undefined behavior:-).
Seriously, it is a form of type punning. a is a float, but a is also a block of memory (typically four bytes) with bits in it. (float&)a means to treat that block of memory as if it were a float (in other words, what it actually is); (int&)a means to treat it as an int. Formally, accessing an object (such as a) through an lvalue expression with a type other than the actual type of the object is undefined behavior, unless the type is a character type. Practically, if the two types have the same size, I would expect the results to be a reinterpretation of the bit pattern.
In the case of a float, the bit pattern contains bits for the sign, an exponent and a mantissa. Typically, the exponent will use some excess-n notation, and only 0.0 will have 0 as an exponent. (Some representations, including the one used on PCs, will not store the high order bit of the mantissa, since in a normalized form in base 2, it must always be 1. In such cases, the stored mantissa for 1.0 will have all bits 0.) Also typically (and I don't know of any exceptions here), the exponent will be stored in the high order bits. The result is when you "type pun" a floating point value to a an integer of the same size, the value will be fairly large, regardless of the floating point value.
The values are different because interpreting a float as an int & (reference to int) throws the doors wide open. a is not an int, so pretty much anything could actually happen when you do that. As it happens, looking at that float like it's an int gives you 1065353216, but depending on the underlying machine architecture it could be 42 or an elephant in a pink tutu or even crash.
Note that this is not the same as casting to an int, which understands how to convert from float to int. Casting to int & just looks at bits in memory without understanding what the original meaning is.