Home > OS >  How to conversionless cast an object in C without using pointers?
How to conversionless cast an object in C without using pointers?

Time:06-08

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,            
  •  Tags:  
  • c
  • Related