Thread: Retypecasting in C

  1. #1
    Registered User
    Join Date
    Mar 2008
    Posts
    10

    Retypecasting in C

    Hi,
    I am facing a memory problem.

    I have defined an array of size 2048 in a structure, which is of type uint8.

    Now in runtime I want to retypecast the same array into either uint16 or uint32 depending on how big my array element is.

    If I retypecast it to uint16 I expect that I will be able to store just 1024 instead of 2048 elements, and this way I can avoid allocating the whole length for uint32 element size, which will be four times of the current size.

    I have tried with void typecasting to int but it gives error because I am indexing the array elements while storing and retireving elements.

    Can anyone help?

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Can you post how you're doing it?

    A few methods come to mind:
    Code:
    uint8 data[2048];
    ((uint16*)data)[42] = 2;
    Code:
    uint8 data[2048];
    uint16 *two = (uint16 *)&data;
    two[42] = 2;
    Code:
    union {
        uint8 one[2048];
        uint16 two[1024];
        uint32 three[512];
    } data;
    
    data.two[42] = 5;
    I think those will work, but I haven't tried them.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Registered User
    Join Date
    Mar 2008
    Posts
    10
    My intended useage:

    while filling up the array:
    /* init stage*/
    if(some condition)
    retypecast to either 16bit or 32 bit.

    Fill the array. Array element size will not shoot the typecasted size.

    /* loop*/
    While accessing access as normal, and pointer name remains the same irrespective of whether it is 8, 16 or 32 bit unsigned.

    if(array[index]) --> should give me the value as per the typecasting done in init stage.
    I cannot add a check
    if(some condition) every time i access as this is a major hit in performance.

    Hope I made it more clear.

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by gunner4life View Post
    While accessing access as normal, and pointer name remains the same irrespective of whether it is 8, 16 or 32 bit unsigned.
    You can't do that.

    C doesn't allow a variable declared with one type to magically behave as if it is another type. The type of a variable is fixed when you define (i.e. create) it and persists until it is destroyed (eg passes out of scope).

    How about explaining what you're actually trying to achieve?
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by dwks View Post
    Code:
    uint8 data[2048];
    uint16 *two = (uint16 *)&data;
    two[42] = 2;
    Although, data = uint8* and &data = (uint8*)[2048] (I believe that's how the type is... typed), ie not the same type.
    I'd do it like this:
    Code:
    uint8 data[2048];
    uint16* two = (uint16*)data;
    two[42] = 2;
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by grumpy View Post
    You can't do that.
    Oh?
    Quote Originally Posted by grumpy View Post
    C doesn't allow a variable declared with one type to magically behave as if it is another type. The type of a variable is fixed when you define (i.e. create) it and persists until it is destroyed (eg passes out of scope).
    Code:
    unsigned char block[1024];
    void *p = █
    
    *(int *)p = 1000;
    *(char *)p = 'a';
    Magic!?


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

  7. #7
    Registered User
    Join Date
    Mar 2008
    Posts
    10
    I am still not able to know from the replies if i can actually do such a thing.

    Code:
    Code:
    typedef <struct>
    {
     ..
    ..
    ..
     uint8 array[2048]
     .. ..
     ..
    ..
    ..
    }struct;
    
    
    /* Init stage */
    
    void foo()
    {
        struct *ptr;
        x = num1;
        y = num2;
    
       if(y/x is >limit1 && < limit 2)    
          <retypecast ptr->array to uint16>;
       if(y/x > limit2)
         <retypecast ptr->array to uint32>;
    
       .........
    ........
    ......
       <Fill in array elements>
    Here my element would be either 8 bit, 16 or 32 bit depending on y/x. And hence I would require an array of minimum required element size. No. of elements would reduce automatically if I were to store 16 bit and still less for 32 bit elements.

    Code:
       /*After Init*/
     while (loop)
        <acces array>
    Here I would like to avoid typecasting and checking for same y/x conditions to acess different arrays due to performance issues. Basically I want to typecast an array from a previously defined uint8 type to either uint16 or 32 at runtime. and only once at init stage. No of bytes allocated in the array remains the same in any case.

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    unsigned char bytes[ BYTE_COUNT ];
    typeX *p, *end;
    p = bytes;
    end = bytes + ( BYTE_COUNT / sizeof *p );
    Something like that perhaps?
    Code:
    while( p < end )
    {
        dostuff( p++ );
    }

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

  9. #9
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by quzah View Post
    Oh?
    Code:
    unsigned char block[1024];
    void *p = &block;
    
    *(int *)p = 1000;
    *(char *)p = 'a';
    Magic!?


    Quzah.
    No, not magic. But not what is asked for.

    gunner4life wants to do this;
    Code:
    int main()
    {
        uint16 data[2048];   /* data decclared as an array here */
    
        some_magic(); 
    
        data[42] = something();    /* data[42] is of type uint32 here */
    }
    He essentially want to reuse the array name as if it was a different type - where the two bits coloured in red are the same name within the same scope, but different type at the two lines. There is no way of implementing some_magic() to achieve that.
    Last edited by grumpy; 06-11-2009 at 06:11 AM.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  10. #10
    Registered User
    Join Date
    Mar 2008
    Posts
    10
    Firstly my loop counter doesnt depend on bytes in the array. Accessing memories (in units of elements and not bytes) which are not filled at init stage is taken care inside the loop.

    Secondly
    p++ will give different results for different type of array. I want p++ to automatically increment by element and not by a preset no. of bytes calculated with conditions.

    Code:
    inc_value = 1;
    if(y/x > limit1 and < limit2)
            inc_value = 2;
    
    if(y/x > limit2)
            inc_value = 4;
    This would result in something like this while accessing the array.
    val = *(array + inc_value*index);

    I am accessing the array elements many times in one iteration. Such an operation to find the offset is almost equivalent to assembly programming, and multiplication is very costly.

    I hope I am making sense.

  11. #11
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by grumpy View Post
    No, not magic. But not what is asked for.

    gunner4life wants to do this;
    Code:
    int main()
    {
        uint16 data[2048];   /* data decclared as an array here */
    
        some_magic(); 
    
        data[42] = something();    /* data[42] is of type uint32 here */
    }
    He essentially want to reuse the array name as if it was a different type - where the two bits coloured in red are the same name within the same scope, but different type at the two lines. There is no way of implementing some_magic() to achieve that.
    Not in that way, but you could probably change it so the last part that fills in the array is in separate functions (one for each data type you're interested in) and pass data to the appropriate function.
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  12. #12
    Registered User
    Join Date
    Mar 2008
    Posts
    10
    Btw its is not necessary that I should access the array by the same name as it is declared in.

    Code:
    uint8 array[2048];
    Something like this would also do.
    Code:
    void *temp;
    temp = (uint16 *)array;
    /*then use as normal*

    But it gives error message as "Unknown size" on line
    Code:
    val = temp[i];
    My guess is is its because I am not allocating any memory for the temp ptr. But Since I am in a memory crunch (as well as performance) I cannot allocate any new memory.

    Code:
    int main()
    {
        uint16 data[2048];   /* data decclared as an array here */
    
        some_magic(); 
    
        data[42] = something();    /* data[42] is of type uint32 here */
    }
    Basically its ok if while accessing its a pointer/array with another name but as an alias to the original array. I hope its not the same thing as accessing through the same name.

  13. #13
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by gunner4life View Post
    p++ will give different results for different type of array. I want p++ to automatically increment by element and not by a preset no. of bytes calculated with conditions.


    I hope I am making sense.
    You make sense, but it is not clear what you are having problems with. It should be easy to find out if in this example given by dwks:
    Code:
    uint8 data[2048];
    ((uint16*)data)[42] = 2;
    [42] is the same as data[42] -- in which case this is the same as
    Code:
    (unint16*)data[42];
    It could turn out to be data[84], in which case it accomplishes something different.

    I am sure you can deal with your issue as described by using typecasting and sizeof(). Put the relevant "sizeof"s into variables if there are lots of fast iterations using that value.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  14. #14
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I am pretty sure this is meaningless:

    Quote Originally Posted by gunner4life View Post
    Code:
    void *temp;
    temp = (uint16 *)array;
    Also, you do *not* need to allocate more memory to temp; it points to the allocated memory in array. You actually *cannot*, look:
    Code:
    temp = array;
    temp = malloc(xx);
    This would be pointless; either it points to array, or it points to it's own block of memory, not both. The second line reassigns temp -- it will no longer point the value of it's previous assignment.

    You are going about this the wrong way by trying to affect a change on the level of the array pointer. You will have to implement the difference between the datatypes when looping thru the array, ie, on the level of the individual element.
    Last edited by MK27; 06-11-2009 at 06:41 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  15. #15
    Registered User
    Join Date
    Mar 2008
    Posts
    10
    Quote Originally Posted by MK27 View Post
    I am pretty sure this is meaningless:



    Also, you do *not* need to allocate more memory to temp; it points to the allocated memory in array. You actually *cannot*, look:
    Code:
    temp = array;
    temp = malloc(xx);
    This would be pointless; either it points to array, or it points to it's own block of memory, not both. The second line reassigns temp -- it will no longer point the value of it's previous assignment.

    You are going about this the wrong way by trying to affect a change on the level of the array pointer. You will have to implement the difference between the datatypes when looping thru the array, ie, on the level of the individual element.

    But the point is I will not know whether I have to typecast the pointer to a uint16 or uint32. It is only known at run time. So to implement at element level it would have to be something like this??

    Code:
    if (within limits)
        val = *((uint16 *)void_ptr+offset);
    else
       val = *((uint32 *)void_ptr+offset);
    ?????? OMG!

Popular pages Recent additions subscribe to a feed