Structure definition

This is a discussion on Structure definition within the C Programming forums, part of the General Programming Boards category; I have a character array that contains information that I want to populate into a structure. The array has the ...

  1. #1
    Unregistered
    Guest

    Unhappy Structure definition

    I have a character array that contains information that I want to populate into a structure. The array has the following data
    0x01 0x7b 0xC0 0x08
    How do I write a structure that will retreive information from this array in the following manner -->

    the first three bits contain information a
    the next 5 bits contain information b
    the next 12 bits contain information c
    the next 12 bits contain information d

    typedef struct
    {
    unsigned long a : 3; // (0 for data given above)
    unsigned long b : 5; // (1 for data given above)
    unsigned long c : 12; // (7bc for data given above)
    unsigned long d : 12; // (8 for data given above)
    } Data;

    does not seem to work. I work on an intel machine. Appreciate any help.

  2. #2
    Green Member Cshot's Avatar
    Join Date
    Jun 2002
    Posts
    892
    There's no standard way to write to your pre-defined structure. You can use memcpy but that will swap your bytes. However, the most portable way to do it is to shift to each field individually like this:

    Code:
    #include <stdio.h>
    
    typedef struct 
    { 
       unsigned int a : 3; // (0 for data given above) 
       unsigned int b : 5; // (1 for data given above) 
       unsigned int c : 12; // (7bc for data given above) 
       unsigned int d : 12; // (8 for data given above) 
    } Data; 
    
    int main()
    {
       Data d;
       unsigned int i;
       unsigned char a[4] = {0x01, 0x7b, 0xc0, 0x08};
    
       i = a[0] << 24 | a[1] << 16 | a[2] << 8 | a[3];
       d.a = i >> (32 - 3) & 0x07;
       d.b = i >> (32 - 3 - 5) & 0x1f;
       d.c = i >> (32 - 3 - 5 - 12) & 0xfff;
       d.d = i & 0xfff;
    
       printf("a = %x\nb = %x\nc = %x\nd = %x\n", d.a, d.b, d.c, d.d);
    
       return 0;
    }

  3. #3
    Registered User
    Join Date
    Jul 2002
    Posts
    15
    I tried this out and it works great ... thanks ... But I have another request. Can I acheive the result to this problem without so many shifting operations by just reshuffling the order of members in my structure?

    1) I am not allowed to change the ordering of the bytes in the char array because another application uses this.
    2) But I am allowed to change the ordering of the structure itself.
    3) This said, I can copy over the data to another array temporarily and performing swab operations and bit reversals.

    Thanks for your earlier reply

  4. #4
    Green Member Cshot's Avatar
    Join Date
    Jun 2002
    Posts
    892
    What function are you trying to use to copy it over? Shifting is still the best way to go. You have control over the way it copies and it's portable.

  5. #5
    Registered User
    Join Date
    Jul 2002
    Posts
    15
    I use memcpy to copy between character arrays. I dont want to use the shifting route because that will mean that I need to know size of each data type. I prefer to change the structure itself so that it gets aligned into the right fields by virtue of the position of the field in the structure. Is this possible? This code need not be portable outside of the intel platform which is why I am okay with changing the structure itself.

    This is what I need to do -->

    1) get the data in as a character array .. this array contains info as in example character array ...
    2) I then need to cast to a structure that contains a,b,c,d etc...
    3) I then use this structure from now on to get values of a/b/c/d
    4) Now if I create an instance of this structure and populate it with values, then memcpying this structure to a char array should give me back the array as shown in the example.

  6. #6
    Green Member Cshot's Avatar
    Join Date
    Jun 2002
    Posts
    892
    I'm not sure if it's possible to memcpy directly from an array to your structure without totally changing the way your structure looked. Because memcpy swap bytes when you do a copy, you'll get your bits split up between fields.

    I suggest you write a couple of generic functions to copy from a char to a structure and a structure to a char. Pass in 4 fields. The source, destination, array of field sizes, and size of array.

  7. #7
    Registered User
    Join Date
    Jul 2002
    Posts
    15
    When you say drastically change the structure, do you mean the sizes also ... because I am ok to changing the structures ... This structure is local to my application. its only the char array that goes out that will have to be consistent. Normally I dont do a memcpy I just directly cast.

    char a[4]={0x01, 0x7b, 0xc0, 0x08};
    ...
    ...

    Data * pData = (Data*) str;
    pData->a ...
    pData->b ...

    Now is it possible to define a structure that will get data into the members as expected. Obviously I amassuming that the size of fields cannot change because you have to manipulate all four bytes and they are filled to max capacity.

    Greatly Appreciate your help ... thanks once again

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Actually, you can just use direct assignment. The only thing you need to keep in mind is that where you're assigning to may not have as many bits as the data being copied. Anyway, if you already know what the values are, just do:

    d.a = a[0];
    d.b = a[1];
    d.c = a[2];
    d.d =a[3];

    There is no need to mask here. You have the end valus, just assign them.

    Quzah.
    Hope is the first step on the road to disappointment.

  9. #9
    Green Member Cshot's Avatar
    Join Date
    Jun 2002
    Posts
    892
    He can't use direct assignment because some of the fields are less than 8 bits and some require bits from 2 array slots.

    If you want to be able to use memcpy, you'll have to figure out on a case-by-case basis on how to define your structure. This requires a lot more work than shifting the values yourself.

  10. #10
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    He can't use direct assignment because some of the fields are less than 8 bits and some require bits from 2 array slots.
    Yes, you can. The only warning you'll get (read that again: warning, not error) is that some truncation may occur.

    If the assigned value falls in the number of bits that the lvalue contans, it'll work fine.

    Perhaps you should try it yourself. It will work. If the value in X only uses the first N bytes, where N is the number of bits in the lvalue you're assigning to, you will have a prefect assignment. (IE: No data loss.)

    If however, you are assigning a value that contains a higher number, you'll get truncation.

    Can you say "type cast"? I thought you could! This is the exact same thing as a type cast. You can typecast an int to a char, but you may run into truncation.

    It's as simple as that.

    Quzah.
    Hope is the first step on the road to disappointment.

  11. #11
    Green Member Cshot's Avatar
    Join Date
    Jun 2002
    Posts
    892
    Yes you can do that but you would get incorrect results. Maybe you're misunderstanding what he wants.

    If we do it the way you suggest:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    typedef struct 
    { 
       unsigned int a : 3; // (0 for data given above) 
       unsigned int b : 5; // (1 for data given above) 
       unsigned int c : 12; // (7bc for data given above) 
       unsigned int d : 12; // (8 for data given above) 
    } Data; 
    int main()
    {
       Data d;
       unsigned char a[4] = {0x01, 0x7b, 0xc0, 0x08};
    
       d.a = a[0];
       d.b = a[1];
       d.c = a[2];
       d.d = a[3];
    
       printf("a = %x\nb = %x\nc = %x\nd = %x\n", d.a, d.b, d.c, d.d);
    
       return 0;
    }
    Output:
    a = 1 (should be 0)
    b = 1b (should be 1)
    c = c0 (should be 7bc)
    d = 8

    Anyway, if you already know what the values are
    He doesn't know what the values are though. Depending on what the values are, the way the chars are assigned will be different.

    Since that first field is only 3 bits, it'll take the first 3 bits and then the next 5 bits of a[0] will go in the next field.

  12. #12
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Output:
    a = 1 (should be 0)
    b = 1b (should be 1)
    c = c0 (should be 7bc)
    d = 8

    Oh really? How do you figure:

    unsigned char a[4] = {0x01, 0x7b, 0xc0, 0x08};

    The only one that gives you problems is the second one. Want to know why?

    2|4|8|16|32 is NOT able to store 123. You cannot pack six bits into the space for five.

    I am not wrong here. The output is exactly the way it should be. You cannot fix six bits into the space of five. Period.

    printf("%d", 0x7b );

    Understand the problem?

    Quzah.
    Hope is the first step on the road to disappointment.

  13. #13
    Green Member Cshot's Avatar
    Join Date
    Jun 2002
    Posts
    892
    I understand what you're saying quzah. But that's not what he wants.

    This structure is 32 bits.
    unsigned int a : 3;
    unsigned int b : 5;
    unsigned int c : 12;
    unsigned int d : 12;

    Now in his char array {0x01, 0x7b, 0xc0, 0x08} also contains 32 bits.
    He wants to put those 32 bits into the 32 bits of the structure while keeping the bit order.
    the first three bits contain information a
    the next 5 bits contain information b
    the next 12 bits contain information c
    the next 12 bits contain information d
    So a = the first 3 bits of 0x01 which is 000b
    b = the next 5 bits of 0x01 which is 00001b
    and so on

  14. #14
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Then you're all doing it the hard way.
    Code:
    union x
    {
        struct
        {
            unsigned int a:3;
            unsigned int b:5;
            unsigned int c:12;
            unsigned int d:12;
        } a;
        unsigned char b[4];
    };
    
    union x yz;
    
    [edit]
    Apparently you have to assign them individually. In either case:
    
    yz.b[0] = 0x01;
    yz.b[1] = 0x7b;
    yz.b[2] = 0xc0;
    yz.b[3] = 0x08;
    [/edit]
    Simplicity.

    Quzah.
    Last edited by quzah; 07-30-2002 at 06:38 PM.
    Hope is the first step on the road to disappointment.

  15. #15
    Green Member Cshot's Avatar
    Join Date
    Jun 2002
    Posts
    892
    Unfortunately that would give you the same result as a memcpy.
    If you printf a thru d you'll get:
    a = 1
    b = 0
    c = 7b
    d = 8c
    Which is not what he wanted.

    Although your memory location would contain the right bits.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Errors including <windows.h>
    By jw232 in forum Windows Programming
    Replies: 4
    Last Post: 07-29-2008, 02:29 PM
  2. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 07:39 AM
  3. DLL compiling question
    By Noose in forum Windows Programming
    Replies: 2
    Last Post: 12-16-2004, 07:16 AM
  4. Warnings, warnings, warnings?
    By spentdome in forum C Programming
    Replies: 25
    Last Post: 05-27-2002, 07:49 PM
  5. gcc problem
    By bjdea1 in forum Linux Programming
    Replies: 13
    Last Post: 04-29-2002, 07:51 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21