cast question

Discussion in 'C Programming' started by David Mathog, Nov 18, 2010.

  1. David Mathog

    David Mathog Guest

    I am trying to force the compiler to be sloppy with types to allow 16
    byte chunks of
    memory to be accessed in some places as in int, and in others as a
    char, and so forth.
    Mixed in with this is the gcc vector extension, but I don't think that
    is the problem.
    Here is a bit of sample code

    8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    /* assumes int/uint are 4 bytes, ll/ull are 8*/
    typedef union {
    int v __attribute__ ((__vector_size__ (16)));
    int a[4];
    unsigned int u[4];
    long long l[2];
    unsigned long long U[2];
    }__av4si;

    typedef long long __m128i __attribute__ ((__vector_size__ (16),
    __may_alias__));

    int main(void){
    int i,j;
    int array[4]={1,2,4,8};
    #ifdef BAD
    __m128i result;
    #else
    __av4si result;
    #endif
    memcpy((void*)&result,&array[0],16);
    for(j=0;j<4;j++){
    i=((__av4si)result).a[j];
    (void) fprintf(stdout, "A[%d] is %X\n",j,i);
    }
    }
    8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<

    # gcc -o short short.c
    # ./short
    A[0] is 1
    A[1] is 2
    A[2] is 4
    A[3] is 8
    # gcc -DBAD -o short short.c
    short.c: In function 'main':
    short.c:28: error: cast to union type from type not present in union

    And there's the problem. The __m128i type is a sort of generic bag
    for holding 16 bytes
    of data, but I need a way to force it to be interpreted different
    ways. Unfortunately in the many
    functions which use it, none of which I can change, __m128i variables
    are always passed by value. I am looking for a way to tell the
    compiler to access it as in the example above, that is, without having
    to resort to doing something like using memcpy to pull the data into
    an array of the appropriate type. The only other approach that I have
    come up with so far that works is:

    i=(*((__av4si *)(&result))).a[j];

    which is pretty hideous. In fact, if one has to resort to making
    pointers and then changing the type that way the typedef union isn't
    needed at all:

    i=((int *)&result)[j];

    Both of the last forms work when compiled with or without -DBAD. Is
    there a cast syntax
    more like this

    i=((__av4si)result).a[j];

    that is, no "&" employed, that will compile if "result" is an __m128i
    variable?

    Thanks,

    David Mathog
    David Mathog, Nov 18, 2010
    #1
    1. Advertising

  2. David Mathog

    Stefan Ram Guest

    David Mathog <> writes:
    >typedef union


    »When a value is stored in a member of an object of union type,
    the bytes of the object representation that do not
    correspond to that member but do correspond to other
    members take unspecified values«
    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    ISO/IEC 9899:1999 (E), 6.2.6.1#7

    But your C implementation might specified the values for this case.

    Otherwise, pointer-casting should be fine. - But, I am not sure:
    When a pointer to type A is cast to a pointer to type B and then
    an attempt to read a B value is made via this pointer, does
    ISO/IEC 9899:1999 (E) specify anything more about the result
    than in the case of unions?

    For an example C program to read single bits of int- and double-
    values using casts, search for »bitprint.c« on

    http://www.purl.org/stefan_ram/pub/formal_typwandlung_de

    . (The two outputs are from two C implementations.)

    If the value is (at most) implementation specified anyway, what
    would be the better style to convert from one interpretation
    of a bit pattern at a certain memory location to another
    interpretation: a union or a pointer-type-cast?
    Stefan Ram, Nov 18, 2010
    #2
    1. Advertising

  3. David Mathog

    BartC Guest

    "David Mathog" <> wrote in message
    news:...
    > I am trying to force the compiler to be sloppy with types to allow 16
    > byte chunks of
    > memory to be accessed in some places as in int, and in others as a
    > char, and so forth.


    > i=((__av4si)result).a[j];


    Try this instead:

    i=(*((__av4si*)&result)).a[j];

    For a simpler example, if you have an int you want to interpret as a float,
    without any conversions, it would look like:

    int a;
    float x;

    x=*(float*)&a;

    --
    Bartc
    BartC, Nov 18, 2010
    #3
  4. David Mathog

    Tim Rentsch Guest

    David Mathog <> writes:

    > I am trying to force the compiler to be sloppy with types to allow 16
    > byte chunks of
    > memory to be accessed in some places as in int, and in others as a
    > char, and so forth.
    > Mixed in with this is the gcc vector extension, but I don't think that
    > is the problem.
    > Here is a bit of sample code
    >
    > 8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<
    > #include <stdio.h>
    > #include <stdlib.h>
    > #include <string.h>
    >
    > /* assumes int/uint are 4 bytes, ll/ull are 8*/
    > typedef union {
    > int v __attribute__ ((__vector_size__ (16)));
    > int a[4];
    > unsigned int u[4];
    > long long l[2];
    > unsigned long long U[2];
    > }__av4si;
    >
    > typedef long long __m128i __attribute__ ((__vector_size__ (16),
    > __may_alias__));
    >
    > int main(void){
    > int i,j;
    > int array[4]={1,2,4,8};
    > #ifdef BAD
    > __m128i result;
    > #else
    > __av4si result;
    > #endif
    > memcpy((void*)&result,&array[0],16);
    > for(j=0;j<4;j++){
    > i=((__av4si)result).a[j];
    > (void) fprintf(stdout, "A[%d] is %X\n",j,i);
    > }
    > }
    > 8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<
    >
    > # gcc -o short short.c
    > # ./short
    > A[0] is 1
    > A[1] is 2
    > A[2] is 4
    > A[3] is 8
    > # gcc -DBAD -o short short.c
    > short.c: In function 'main':
    > short.c:28: error: cast to union type from type not present in union
    >
    > And there's the problem. The __m128i type is a sort of generic bag
    > for holding 16 bytes
    > of data, but I need a way to force it to be interpreted different
    > ways. Unfortunately in the many
    > functions which use it, none of which I can change, __m128i variables
    > are always passed by value. I am looking for a way to tell the
    > compiler to access it as in the example above, that is, without having
    > to resort to doing something like using memcpy to pull the data into
    > an array of the appropriate type. The only other approach that I have
    > come up with so far that works is:
    >
    > i=(*((__av4si *)(&result))).a[j];
    >
    > which is pretty hideous. In fact, if one has to resort to making
    > pointers and then changing the type that way the typedef union isn't
    > needed at all:
    >
    > i=((int *)&result)[j];
    >
    > Both of the last forms work when compiled with or without -DBAD. Is
    > there a cast syntax
    > more like this
    >
    > i=((__av4si)result).a[j];
    >
    > that is, no "&" employed, that will compile if "result" is an __m128i
    > variable?


    First, the casts you're trying to use are not standard C, which
    doesn't allow casting to a union type.

    Second, if you still want to use this approach, I expect you will
    find this definition for the union type

    typedef union {
    int v __attribute__ ((__vector_size__ (16)));
    int a[4];
    unsigned int u[4];
    long long l[2];
    unsigned long long U[2];
    __m128i what_ever;
    }__av4si;

    will allow the casts you want to be used (assuming of course that
    using the __m128i type as the type of one of the members of the
    union __av4si type is feasible in your program).

    Third, did you notice the text of the error message:

    error: cast to union type from type not present in union
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    Good luck!
    Tim Rentsch, Nov 18, 2010
    #4
  5. David Mathog

    David Mathog Guest

    On Nov 17, 11:09 pm, Tim Rentsch <> wrote:
    > First, the casts you're trying to use are not standard C, which
    > doesn't allow casting to a union type.


    More on that later

    >
    > Second, if you still want to use this approach, I expect you will
    > find this definition for the union type
    >
    >     typedef union {
    >       int  v __attribute__ ((__vector_size__ (16)));
    >       int                a[4];
    >       unsigned int       u[4];
    >       long long          l[2];
    >       unsigned long long U[2];
    >       __m128i            what_ever;
    >     }__av4si;


    Also suggested by Philip Lantz in an email. That actually did work
    and here's the sample code
    that shows it for the general 16 byte situation:
    8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<
    /* short2.c */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h> /* for memcpy */
    typedef double __m128d __attribute__ ((__vector_size__ (16),
    __may_alias__));
    typedef long long __m128i __attribute__ ((__vector_size__ (16),
    __may_alias__));

    /* assumes an int/float are 4 bytes, double/long are 8, short is 2,
    char is 1*/
    typedef union {
    __m128i vi;
    __m128d vd;
    char c[16];
    unsigned char uc[16];
    short s[8];
    unsigned short us[8];
    int i[4];
    unsigned int ui[4];
    long long l[2];
    unsigned long long ul[2];
    float f[4];
    double d[2];
    }__all16;

    int main(void){
    __m128i result;
    int i;
    int iarray[4]={1,2,3,4};
    float farray[4]={1.,2.,3.,4.};
    double darray[2]={1.,2.};
    long long larray[2]={1,2};
    short sarray[8]={1,2,3,4,5,6,7,8};
    char carray[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    memcpy(&result,&larray[0],16);
    for(i=0;i<2;i++){fprintf(stdout, "llong [%d] is %llX\n",i,
    ((__all16)result).l); }
    for(i=0;i<2;i++){fprintf(stdout, "ullong [%d] is %llX\n",i,
    ((__all16)result).ul); }
    memcpy(&result,&darray[0],16);
    for(i=0;i<2;i++){fprintf(stdout, "double [%d] is %f\n",i,
    ((__all16)result).d); }
    memcpy(&result,&iarray[0],16);
    for(i=0;i<4;i++){fprintf(stdout, "int [%d] is %X\n",i,
    ((__all16)result).i); }
    for(i=0;i<4;i++){fprintf(stdout, "uint [%d] is %X\n",i,
    ((__all16)result).ui); }
    memcpy(&result,&farray[0],16);
    for(i=0;i<4;i++){fprintf(stdout, "float [%d] is %f\n",i,
    ((__all16)result).f); }
    memcpy(&result,&sarray[0],16);
    for(i=0;i<8;i++){fprintf(stdout, "short [%d] is %X\n",i,
    ((__all16)result).s); }
    for(i=0;i<8;i++){fprintf(stdout, "ushort [%d] is %X\n",i,
    ((__all16)result).us); }
    memcpy(&result,&carray[0],16);
    for(i=0;i<16;i++){fprintf(stdout, "char [%d] is %X\n",i,
    ((__all16)result).c); }
    for(i=0;i<16;i++){fprintf(stdout, "uchar [%d] is %X\n",i,
    ((__all16)result).uc); }
    exit(EXIT_SUCCESS);
    }

    8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<8<

    % gcc -std=c99 -Wall -msse2 -o short2 short2.c
    (no warning or error messages)
    % ./short2
    (correct, all fields occupied by the index value + 1).

    So this approach does work. Now back to the standards question, you
    are right because:

    gcc -std=c99 -pedantic -Wall -msse2 -o short2 short2.c
    short2.c: In function 'main':
    short2.c:36: warning: ISO C forbids casts to union type
    short2.c:37: warning: ISO C forbids casts to union type
    short2.c:39: warning: ISO C forbids casts to union type
    etc.

    Using the form below does not run afoul of the standards, at least not
    enough to
    trigger a compiler warning with -std=c99 -pedantic :

    #define AS_INT4(a,b) ((int *)&(a))[(b)]
    for(i=0;i<4;i++){fprintf(stdout, "int*& [%d] is %X
    \n",i,AS_INT4(result,i)); }

    I suppose there would be alignment issues if an arbitrary pointer into
    a character array was
    accessed in this manner, but for data already forced onto 16 byte
    boundaries that should not
    come up.

    Thanks,

    David Mathog
    David Mathog, Nov 18, 2010
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. VB Programmer

    Question: Invalid Cast Exception Error

    VB Programmer, Oct 28, 2003, in forum: ASP .Net
    Replies:
    4
    Views:
    1,340
    VB Programmer
    Oct 28, 2003
  2. Christopher Benson-Manica

    Quick cast style question

    Christopher Benson-Manica, Apr 30, 2004, in forum: C++
    Replies:
    15
    Views:
    518
    Jake Montgomery
    May 4, 2004
  3. MSG

    to cast or not to cast malloc ?

    MSG, Feb 6, 2004, in forum: C Programming
    Replies:
    38
    Views:
    1,048
    Dan Pop
    Feb 10, 2004
  4. EvilRix
    Replies:
    8
    Views:
    606
    Martin Dickopp
    Feb 14, 2004
  5. Pavel
    Replies:
    7
    Views:
    503
    Pavel
    Sep 19, 2010
Loading...

Share This Page