0

I have an unsigned char array with values as below:

u_char *t_header[4]; //filled with values 0x00000047,0x00000004,0x00000093,0x00000012

I have a struct as below:

            #pragma pack(push, 1)
            typedef struct th_struct {
                unsigned s_byte : 8;
                unsigned t_e_indicator : 1;
                unsigned p_u_s_indicator : 1;
                unsigned t_priority : 1;
                unsigned id : 13;
                unsigned t_s_control : 2;
                unsigned a_f_control : 2;
                unsigned c_counter : 4; 
            }th_struct;
            #pragma pack(pop)

I am trying to fill the struct fields as below:

            const struct  th_struct *tsh;
            tsh = (struct th_struct*)(t_header);

It fills the tsh->s_byte with 71 = 0x47 in hex as expected but the rest of the fields are all 0.

What i have to do to fill struct th_struct *tsh with the u_char *t_header[4] values correctly as below?

0100 0111 .... .... .... .... .... .... = (0x00000047) tsh->s_byte .... .... 0... .... .... .... .... .... = 0 tsh->t_e_indicator .... .... .0.. .... .... .... .... .... = 0 tsh->p_u_s_indicator .... .... ..0. .... .... .... .... .... = 0 tsh->t_priority .... .... ...0 0100 1001 0011 .... .... = (0x00000493) tsh->id .... .... .... .... .... .... 00.. .... = (0x00000000) tsh->t_s_control .... .... .... .... .... .... ..01 .... = (0x00000001) tsh->a_f_control .... .... .... .... .... .... .... 0010 = 2 tsh->c_counter

Thank you!

swartkatt
  • 368
  • 3
  • 10
  • 2
    First of all It really depends on endianness of your platform... – LPs Dec 19 '16 at 11:03
  • 1) You don't have a uchar array 2) You can't fill a struct by assigning something to a pointer to the struct. Please show a complete code example. – Support Ukraine Dec 19 '16 at 11:05
  • 1
    `sizeof(th_struct) = 4` and `sizeof(t_header) = 32` – JMA Dec 19 '16 at 11:08
  • 1
    second `u_char *t_header[4];` is probably **32 bytes** that cannot fit **32 bits** structure.... – LPs Dec 19 '16 at 11:09
  • Thank you for your answers. I see that `sizeof(th_struct) = 4 and sizeof(t_header) = 32` are not same. I think i have to convert the t_header array to something in 4 bytes something like this `0x47049312` but how? – swartkatt Dec 19 '16 at 11:54
  • @swartkatt You currently have `u_char *t_header[4];` which means 4 pointers to u_char because of the `*`. You probably want `u_char t_header[4]`, i.e. no `*` – Support Ukraine Dec 19 '16 at 12:12
  • http://stackoverflow.com/questions/15136426/memory-layout-of-struct-having-bitfields – Support Ukraine Dec 19 '16 at 12:41
  • Thank you 4386427. Now i have `t_header[4]` with values `71,4,147,18` ` sizeof(t_header) = 4; and sizeof(th_struct) = 4;` are in same size After `const struct th_struct *tsh; tsh = (struct th_struct*)(t_header);` - `tsh` has values `71,0,0,1,4704,2,0,1` where `71,0,0,0,1171,0,1,2` is expected. Why? – swartkatt Dec 19 '16 at 14:15

2 Answers2

1

You can do something like this:

struct  th_struct t_header = {
    .s_byte = 0x47,
    .t_e_indicator = 0,
    .p_u_s_indicator = 0,
    .t_priority = 0,
    .id = 0x00000493,
    .t_s_control = 0,
    .a_f_control = 1,
    .c_counter = 2 };

and then: const struct th_struct* tsh = &t_header;

I think it's easier.

You must change the way you assing for sometinh like this:

u_char t_header[4];
t_header[0] = 0x47;     // s_byte
t_header[1] = (u_char)
        (0x00           // t_e_indicator
         | (0x00 << 1)  // p_u_s_indicator
         | (0x00 << 2)  // t_priority
         | (0x493 << 3)); // id[0..4]
t_header[2] = (u_char) ((0x493 << 3) >> 8); // id [5..12]
t_header[3] = (u_char)
        (0x00           // t_s_control
        | (0x01 << 2)   // a_f_control
        | (0x02 << 4)); // c_counter

const struct th_struct* tsh = (th_struct*)t_header;

Or change the struct order:

#pragma pack(push, 1)
           typedef struct th_struct2 {
               unsigned s_byte : 8;
               unsigned id1 : 5;
               unsigned t_e_indicator : 1;
               unsigned t_priority : 1;
               unsigned p_u_s_indicator : 1;
               unsigned id2 : 8;
               unsigned c_counter : 4;
               unsigned a_f_control : 2;
               unsigned t_s_control : 2;
           }th_struct2;
           #pragma pack(pop)

where id1 is the higher part od id, and id2 the lower part.

JMA
  • 494
  • 2
  • 13
  • Thank you but i need to assign the values from a `uchar t_header[4]` array. The values are not fixed and they are changing. – swartkatt Dec 19 '16 at 14:28
  • @swartkatt Can it be `uchar t_header[4]`? or must it be `uchar *t_header[4]`? – JMA Dec 19 '16 at 15:21
  • As you and 4386427 told me that the size of `uchar *t_header[4]` is not equal to 4, therefore i think it has to be `uchar t_header[4]`. There is an example i found which looks similar to my situation as below http://users.cs.cf.ac.uk/Dave.Marshall/C/node13.html#fig:drive but why my example is not working? – swartkatt Dec 19 '16 at 15:38
  • I have access to only 1 byte at a time. Therefore to reach 4 bytes i thought to create an array and store the 4 bytes into that array. After it reaches 4 bytes i need to split it into bits as in the structure of `th_struct` to access the structure values for later use by `tsh->s_byte`... Any idea which can accomplish the task is accepted. Thank you! – swartkatt Dec 19 '16 at 15:38
  • I have a `const u_char *pkt_data` in length `1358` i reach each bytes with a for loop as below: `for (int i = 0; i < 5; i++) t_header[i] = pkt_data[i];` and i should do something with this loop or with this `t_header[4]` array. Thank you – swartkatt Dec 19 '16 at 16:00
  • @swartkatt: I'd suggest adding this information to the question to give people more context and produce answers more relevant to you – TriskalJM Dec 19 '16 at 16:16
  • Thank you JMA for all of your efforts to help me. I choose as an answer by 4386427 and TriskalJM because of the implementation simplicity for my task. – swartkatt Dec 19 '16 at 18:29
1

First of all you have a problem here:

u_char *t_header[4];

That is 4 pointers - not 4 u_char. You probably want:

u_char t_header[4];

Next problem is that the layout of bit fields is implementation-dependent.

Consequently, it is a bad idea (in general) to write code that assumes a specific layout. Such code will only be able to run on the specific system used when writing the code, i.e., the code is non-portable.

I recommend that you use the shift operator >> and bitwise and operator & to pick exactly the bits needed:

unsigned char t_header[4] = {0x47, 0x04, 0x93, 0x12};
th_struct tsh;

tsh.s_byte = t_header[0];
tsh.t_e_indicator = (t_header[1] >> 7) & 0x1;
tsh.p_u_s_indicator = (t_header[1] >> 6) & 0x1;
tsh.t_priority = (t_header[1] >> 5) & 0x1;
tsh.id = ((unsigned)(t_header[1] & 0x1f) << 8) + t_header[2];
tsh.t_s_control = (t_header[3] >> 6) & 0x3;
tsh.a_f_control = (t_header[3] >> 4) & 0x3;
tsh.c_counter = t_header[3] & 0xf;

printf("s_byte=%x\n", tsh.s_byte);
printf("t_e_indicator=%x\n", tsh.t_e_indicator);
printf("p_u_s_indicator=%x\n", tsh.p_u_s_indicator);
printf("t_priority=%x\n", tsh.t_priority);
printf("id=%x\n", tsh.id);
printf("t_s_control=%x\n", tsh.t_s_control);
printf("a_f_control=%x\n", tsh.a_f_control);
printf("c_counter=%x\n", tsh.c_counter);

Then you can also avoid having a packed struct.

TriskalJM
  • 2,393
  • 1
  • 19
  • 20
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • I'd assume that @swartkatt knows this won't be portable, but it's a good idea to mention it anyway. It appears they're doing something pretty platform-specific, likely hardware-related. – TriskalJM Dec 19 '16 at 16:15
  • Thank you very much for the help! – swartkatt Dec 19 '16 at 18:30