问题
Can some explain me the behavior of this C program I was trying to understand its behavior...
#include<stdio.h>
float x = 3.33,*y,z;
int *a,b;
int main() {
a = (int *)&x;
b = (int)x;
y = (float *)a;
z = (float)b;
printf("\nOriginal Value of X: %f \ncasting via pointer A:%d and back Y: %f \ndirect casting B:%d and back Z:%f\n",x,*a,*y,b,z);
}
Output:
Original Value of X: 3.330000
casting via pointer A:1079320248 and back Y: 3.330000
direct casting B:3 and back Z:3.000000
OK so why is the value of A
is 1079320248
and its not some random value its always the same for X = 3.33
and it changes if X
is changed to some different value I was expecting something like A
to be 3
but its not.
回答1:
There is no such thing as 'casting via pointer A' happening in your code. You are just forcing the compiler to point a
to a float value, where it is assumed to be pointing to an integer.
Using the page pointed out by Reymond Chen in the comment section, we get the binary representation of 3.33 as:
01000000010101010001111010111000
Now, use this page to find its 32-bit signed integer equivalent. You'll get 1079320248
, which is the exact non-random number that puzzles you.
If this doesn't make any sense to you, let me make it much clearer. Both a
and y
are pointing to the same binary value 01000000010101010001111010111000
, which represents two different values (3.33 as float and 1079320248 as int) depending on the data type you tell the compiler to use for it.
Update:
Just for academic interest, if you want the printf statement to print 3 for A
, replace the third parameter with this:
(int) *((float *)a)
回答2:
TL;DR Casting a pointer to a different non-compatible type and back and then accessing the last one is OK, the problem starts when you try to use the intermediate pointer with non-compatible type.
To elaborate, your code causes undefined behavior because you violate strict aliasing rule.
Quoting C11
, chapter §6.5
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:88)
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
So in your case, for a definition like
float x = 3.33,*y,z;
//....
a = (int *)&x;
b = (int)x;
y = (float *)a;
You are first casting a pointer to float
to an integer pointer and then, casting it back to float *
and according to the rule mentioned in chapter §6.3.2.3/P7
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned 68) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. [...]
So, accessing y
is fine, but not a
. You will face alignment mismatch, which leads to UB. Don't try to do that. Respect the types.
来源:https://stackoverflow.com/questions/44512402/casting-float-to-int-pointer-and-back-to-float