Casting struct into int
Asked Answered
J

5

16

Is there a clean way of casting a struct into an uint64_t or any other int, given that struct in <= to the sizeof int? The only thing I can think of is only an 'ok' solution - to use unions. However I have never been fond of them.

Let me add a code snippet to clarify:

typedef struct {
uint8_t field: 5;
uint8_t field2: 4;
/* and so on... */
}some_struct_t;

some_struct_t some_struct;
//init struct here

uint32_t register;

Now how do i cast some_struct to capture its bits order in uint32_t register.

Hope that makes it a bit clearer.

Jigaboo answered 10/8, 2012 at 14:31 Comment(11)
Not "fond" of unions? A union does exactly what you want to do in a clear, maintainable way. What's just "OK" about that?Seamus
@CareyGregory I suppose its only "ok" because it would imply creating a new union in the code for every struct the OP wants to convert to int. Whereas the memcpy suggestion is less work for each new struct that needs to be convertedJongjongleur
I have no idea how to answer this without knowing what you actually need this for. More information please.Sheeting
There is a way to cast struct pointer to int pointer, but it's very likely to entail undefined behavior. If you are more fond of undefined behavior than of unions, this link shows how to do the hack.Torgerson
@dasblinkenlight +1 just for politics comment <g> I quite like unions, especially for embedded hardware registers and the like, and I don't have to pay any dues or go on strike.Selfemployed
Why stop at using memcpy for just this? You could use some sort of macro editor to modify the source code to use memcpy() calls for all assignments <g>Selfemployed
@DanF: Perhaps less work if there are many structs to be converted, but unlike memcpy, it's impossible to create a buffer overrun with a union. I would expect it would also optimize much better with most compilers.Seamus
Well i decided to stick with unions at the end, that's the cheapest solution after all.Jigaboo
Won't memcpy be alignment dependent?Astylar
I do not understand why you would want to "capture its bits order". What are you really trying to accomplish? I agree with @Sheeting here.Lati
@Astylar no, memcpy is in fact the only way to do it portably (i.e. according to standard) and alignment dependent. Even if old compilers sometimes were buggy in that regard (gcc 3.3 on SPARC didn't handle it correctly with option -O3).Harumscarum
D
35

I've just hit the same problem, and I solved it with a union like this:

typedef union {
    struct {
        uint8_t field: 5;
        uint8_t field2: 4;
        /* and so on... */
    } fields;
    uint32_t bits;
} some_struct_t;

/* cast from uint32_t x */
some_struct_t mystruct = { .bits = x };

/* cast to uint32_t */
uint32_t x = mystruct.bits;

HTH, Alex

Differential answered 7/5, 2013 at 14:27 Comment(0)
W
4

A non-portable solution:

struct smallst {
  int a;
  char b;
};

void make_uint64_t(struct smallst *ps, uint64_t *pi) {
  memcpy(pi, ps, sizeof(struct smallst));
}

You may face problems if you, for example, pack the struct on a little-endian machine and unpack it on a big-endian machine.

Whittaker answered 10/8, 2012 at 14:41 Comment(1)
memcpy() is one of the most portable solutions...Heartwood
F
4

Warning: It can invoke undefined behaviour under certain circumstances using certain compilers. See Andrew Henle's comment. If you will use my answer, learn about -fno-strict-aliasing compiler flag.

You can cast object's pointer to desired type and then dereference it. Also consider your plaftorm's endianness.

Short example using uint16_t:

*(uint16_t *)&my_struct

Detailed example using uint16_t:

#include <stdio.h>
#include <stdint.h>

typedef struct {
    uint8_t field1;
    uint8_t field2;
} MyStruct;

int main() {
    MyStruct my_struct = {0xFA, 0x7D};
    uint16_t num_my_struct = *(uint16_t *)&my_struct;
    printf("%X \n", num_my_struct);  // 7DFA (little-endian machine)

    return 0;
}
Fakieh answered 22/8, 2022 at 19:25 Comment(1)
This answer is a strict-aliasing violation and results in undefined behavior. It can also invoke undefined behavior if the alignment of the structure is not proper for a uint16_t. Two levels of undefined behavior is not good.Heartwood
E
0

you can use pointers and it will be easy for example:

struct s {
    int a:8;
    int b:4;
    int c:4;
    int d:8;
    int e:8; }* st;

st->b = 0x8;
st->c = 1;
int *struct_as_int = st;

hope it helps

Espino answered 25/10, 2016 at 7:0 Comment(1)
That will require a typecast in any conforming compiler, and will also on many compilers require the use of -fno-strict-aliasing or some similar option.Rubidium
N
-1

Using a user-defined static_cast conversion is simpler than both union and reinterpret_cast/pointer casting: https://en.cppreference.com/w/cpp/language/cast_operator

Nickienicklaus answered 21/8, 2023 at 20:18 Comment(2)
The question is tagged c. C doesn't have static_cast, reinterpret_cast, or user-defined conversion functions.Mccarver
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewIlsa

© 2022 - 2024 — McMap. All rights reserved.