I want to cast an object in C to another type without converting the data and without need to use pointers. I know that you can do it in this manner:
float a = 1.2;
int b = *(int*)(&a);
But I would like to be able to do it to literals and structs constructed in place (if thats the right terminology for that). For example (imagine I could reference a literal for a moment):
void somefunc(int i){...}
somefunc(*(int*)(&1.2))
What I mean by constructed in place is, say I have a struct vec2:
struct vec2{
float x,y;
};
I would like to be able to do something like
void somefunc(vec2 v){...}
somefunc(ConversionlessCast(vec2{1.f,2.f}))
Is this possible?
Edit: I'd like to clarify that I do not care if this is safe or not. I just want to know if theres a way to do it. I should clear up that I would like to not have to make staging variables as well.
Edit2: I realize how poorly formulated this question is without an example, and while initially typing out the example I realized what the answer to what I want to use this for is anyways.
I'm playing around with a way to do styling for a ui system I'm developing and want to be able to use one function for setting a style property. I wanted to pass a string then a value and use the string to determine how to interpret the value. It's now obvious that I should use va_args to do so. However I'm still interested in if there's a way to do what I originally asked regardless because my original plan was to use a unioned type that holds all types a property can possibly be, like
struct Property{
union{
u32 val_u32;
f32 val_f32;
//other possible types
};
};
and then use a string that precedes this to choose which value to use. Unfortunately using an initializer list only accepts the first type, a u32. SO I wanted to come up with a way to initialize a property in a manner like
#define Property(x) Property{(magic that reinterprets anything as the first type on property})
Property(vec2{1.f,2.f})
CodePudding user response:
You can reinterpret the bytes of one object as another using a union in a compound literal. In this code:
printf("%d\n", (union { float f; int i; }) {a} .i);
a union is created, and its f
member is initialized with the value of a
. Then the i
member is accessed by .i
. Per C 2018 note 99 to clause 6.5.2.3 4, that reinterprets the bytes with the new type, int
.
(This is for C. The behavior of this is not defined by the C standard.)
CodePudding user response:
Reinterpreting one type as another via pointers is a strict-aliasing violation and triggers undefined behavior and is therefore not safe.
The safe way to do this would be to either use a union:
union u {
int i;
float f;
};
union u x = { .f=1.2f };
int y = x.i;
Or use memcpy
:
float a = 1.2;
int b;
memcpy(&b, &a, sizeof b);
CodePudding user response:
I did a little experiment - I wrote some code that appears to use pointers if you look at the C code, but it doesn't use pointers if you look at the generated assembly code. Here's what I wrote:
static inline int float_to_int(float f) {
return *(int*)(&f);
}
int main(int argc, char **argv) {
printf("%d\n", float_to_int(3.0)); // prints 1077936128
}
And I found this in the code the compiler generated (gcc -O2 -s):
main:
... etc ...
movl $1077936128,