Assigning an array to another array using C's assignment operator

Discussion in 'C Programming' started by Myth__Buster, Feb 1, 2013.

  1. Myth__Buster

    Myth__Buster Guest

    Hi,

    Here is one technique I have thought of to allow the assignment of
    one array to another in an indirect manner as it's not allowed
    directly in C. Before all, I would like to clarify that it's not
    something designed to replace memcpy(). It's a technique to
    illustrate that how good C's rich set of operators are. So, have a
    look and tell me what you think of it. The code has all the
    reasoning for the different operators I have used. Hope they make
    things straightforward.

    Cheers,
    Raghavan

    <code>
    #include <stdio.h>
    // Applicable for arrays which are allocated dynamically also!
    //
    // The struct assignment below might result in the same code
    // as it would if you happened to use memcpy() and the like.
    // But, the purpose here is different!
    //
    // Purpose here is - To show that "C" indirectly allows array
    // to array assignment. :)
    //
    // NOTE: The struct built for this suffers from no padding
    // issues whatsoever since it involves just an array which
    // must be contiguous and hence the compiler is forced not
    // to play with it even if it wants to for whatever reasons!
    //
    // This macro doesn't check for the size of the
    // destination and hence the user of this macro should
    // take care of it.
    //
    // Why the use of comma-expression seemingly dummy
    // one? Well, it is needed to inform the compiler that
    // we are not punning the types but sincerely dealing
    // with the given addresses to just copy data of the
    // given size.
    //
    // Why seemingly useless (void *) casting? Well, again
    // to inform the compiler that we are punning types as
    // said earlier and this cast is required for
    // convincing strict-aliasing=1.
    //
    // And why (void) casting in that comma expression?
    // Well, it is to inform the compiler that we
    // understand and hence ignore the value of it manually,
    // for having no effect.
    //
    // The previous attempt would fail to compile if the
    // size-based macro is used more than once in the same
    // scope. So, I have used __LINE__ macro to build the
    // unique data type in this attempt.
    //
    // Well, the user of this technique can build the
    // required data type with unique name by himself/herself
    // very easily. But, to ease his/her job a little, I am
    // constructing the required unique data type with the
    // help of the macro. And the uniqueness is based on the
    // line number at which this macro gets placed. So, there
    // will be a redefinition of a specific struct type if
    // you happen to use this macro more than once in the
    // same line. However, this limitation shouldn't be the
    // reason not to use this technique which you can as well
    // use directly by building the struct type by yourself
    // in your code wherever you want.
    //
    #define AssignArraysLine(dest, src, line) \
    ( \
    *(struct t##line \
    { \
    char arr[ sizeof(src) ]; \
    } *) ((void)dest, (void *)dest)\
    = \
    *(struct t##line *) \
    ((void)src, (void *)src) \
    )
    #define AssignArraysOfSizeLine(dest, src, size, line) \
    ( \
    *(struct t##line \
    { \
    char arr[ size ]; \
    } *) ((void)dest, (void *)dest)\
    = \
    *(struct t##line *) \
    ((void)src, (void *)src) \
    )
    #define DummyMacro1(b, a, line) AssignArraysLine(b, a, line)
    #define DummyMacro2(b, a, size, line) \
    AssignArraysOfSizeLine(b, a, size, line)
    // Don't get misled by the term static here in the below
    // macro. It's just to signify that it's meant for only
    // arrays defined using C array subscript([]) operator,
    // which includes variable length arrays.
    //
    // NOTE : Don't use the macro more than once in the
    // same line of your source as __LINE__ will be same
    // and hence you would get type-redefinition error.
    //
    // And macros are known for side-effects, so be wary
    // of them or you can just hand-code the comprehensive
    // typecasting the above macro does without any
    // problem - you can just ignore __LINE__ macro as
    // well if you code by hand since you will not
    // deliberately redefine a struct more than once!
    #define AssignStaticArrays(b, a) DummyMacro1(b, a, __LINE__)
    // Universal macro - works for all types of arrays.
    //
    // NOTE : Don't use the macro more than once in the same
    // line of your source as __LINE__ will be same and hence
    // you would get type-redefinition error.
    //
    // And macros are known for side-effects, so be wary of
    // them or you can just hand-code the comprehensive
    // typecasting the above macro does without any problem -
    // you can just ignore __LINE__ macro as well if you code
    // by hand since you will not deliberately redefine a
    // struct more than once!
    #define AssignArraysOfSize(b, a, size) \
    DummyMacro2(b, a, size, __LINE__)
    int main(void)
    {
    int a[ 10 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int b[ sizeof(a) ];
    int i = 0;
    printf("Array a : ");
    while ( i < 10 )
    {
    printf("%d ", a[ i ]);
    i++;
    }
    printf("\n");
    AssignStaticArrays(b, a); // Once more in the
    // same line -
    // AssignStaticArrays(b, a);
    // - Nope!
    i = 0;
    printf("Array b : ");
    while ( i < 10 )
    {
    printf("%d ", b[ i ]);
    i++;
    }
    printf("\n");
    int z[ sizeof(a) ];
    AssignStaticArrays(z, a); // This works as it's on a
    // different line from the
    // previous usage above!
    i = 0;
    printf("Array z : ");
    while ( i < 10 )
    {
    printf("%d ", z[ i ]);
    i++;
    }
    printf("\n");
    int c[ sizeof(a) ];
    AssignArraysOfSize(c, a, sizeof(a)); // Same rules
    // apply to this
    // macro usage
    // as well as
    // above.
    i = 0;
    printf("Array c : ");
    while ( i < 10 )
    {
    printf("%d ", b[ i ]);
    i++;
    }
    printf("\n");
    int d[ sizeof(c) ];
    AssignArraysOfSize(d, c, sizeof(c)); // Works as it's
    // on a different
    // line.
    i = 0;
    printf("Array d : ");
    while ( i < 10 )
    {
    printf("%d ", d[ i ]);
    i++;
    }
    printf("\n");
    return 0;
    }

    </code>
    Myth__Buster, Feb 1, 2013
    #1
    1. Advertising

  2. Myth__Buster

    Myth__Buster Guest

    On Jan 31, 4:08 pm, Myth__Buster <> wrote:
    > Hi,
    >
    > Here is one technique I have thought of to allow the assignment of
    > one array to another in an indirect manner as it's not allowed
    > directly in C. Before all, I would like to clarify that it's not
    > something designed to replace memcpy(). It's a technique to
    > illustrate that how good C's rich set of operators are. So, have a
    > look and tell me what you think of it. The code has all the
    > reasoning for the different operators I have used. Hope they make
    > things straightforward.
    >
    > Cheers,
    > Raghavan
    >
    > <code>
    > #include <stdio.h>
    > // Applicable for arrays which are allocated dynamically also!
    > //
    > // The struct assignment below might result in the same code
    > // as it would if you happened to use memcpy() and the like.
    > // But, the purpose here is different!
    > //
    > // Purpose here is - To show that "C" indirectly allows array
    > // to array assignment. :)
    > //
    > // NOTE: The struct built for this suffers from no padding
    > // issues whatsoever since it involves just an array which
    > // must be contiguous and hence the compiler is forced not
    > // to play with it even if it wants to for whatever reasons!
    > //
    > //       This macro doesn't check for the size of the
    > //       destination and hence the user of this macro should
    > //       take care of it.
    > //
    > //       Why the use of comma-expression seemingly dummy
    > //       one? Well, it is needed to inform the compiler that
    > //       we are not punning the types but sincerely dealing
    > //       with the given addresses to just copy data of the
    > //       given size.
    > //
    > //       Why seemingly useless (void *) casting? Well, again
    > //       to inform the compiler that we are punning types as
    > //       said earlier and this cast is required for
    > //       convincing strict-aliasing=1.
    > //
    > //       And why (void) casting in that comma expression?
    > //       Well, it is to inform the compiler that we
    > //       understand and hence ignore the value of it manually,
    > //       for having no effect.
    > //
    > //       The previous attempt would fail to compile if the
    > //       size-based macro is used more than once in the same
    > //       scope. So, I have used __LINE__ macro to build the
    > //       unique data type in this attempt.
    > //
    > //       Well, the user of this technique can build the
    > //       required data type with unique name by himself/herself
    > //       very easily. But, to ease his/her job a little, I am
    > //       constructing the required unique data type with the
    > //       help of the macro. And the uniqueness is based on the
    > //       line number at which this macro gets placed. So, there
    > //       will be a redefinition of a specific struct type if
    > //       you happen to use this macro more than once in the
    > //       same line. However, this limitation shouldn't be the
    > //       reason not to use this technique which you can as well
    > //       use directly by building the struct type by yourself
    > //       in your code wherever you want.
    > //
    > #define AssignArraysLine(dest, src, line)               \
    >                         (                              \
    >                          *(struct t##line               \
    >                          {                              \
    >                              char arr[ sizeof(src) ];   \
    >                          } *) ((void)dest, (void *)dest)\
    >                                           =             \
    >                          *(struct t##line *)            \
    >                               ((void)src, (void *)src)  \
    >                         )
    > #define AssignArraysOfSizeLine(dest, src, size, line)   \
    >                         (                              \
    >                          *(struct t##line               \
    >                          {                              \
    >                              char arr[ size];          \
    >                          } *) ((void)dest, (void *)dest)\
    >                                           =             \
    >                          *(struct t##line *)            \
    >                               ((void)src, (void *)src)  \
    >                         )
    > #define DummyMacro1(b, a, line) AssignArraysLine(b, a, line)
    > #define DummyMacro2(b, a, size, line) \
    >                     AssignArraysOfSizeLine(b, a, size, line)
    > // Don't get misled by the term static here in the below
    > // macro. It's just to signify that it's meant for only
    > // arrays defined using C array subscript([]) operator,
    > // which includes variable length arrays.
    > //
    > // NOTE : Don't use the macro more than once in the
    > // same line of your source as __LINE__ will be same
    > // and hence you would get type-redefinition error.
    > //
    > // And macros are known for side-effects, so be wary
    > // of them or you can just hand-code the comprehensive
    > // typecasting the above macro does without any
    > // problem - you can just ignore __LINE__ macro as
    > // well if you code by hand since you will not
    > // deliberately redefine a struct more than once!
    > #define AssignStaticArrays(b, a) DummyMacro1(b, a, __LINE__)
    > // Universal macro - works for all types of arrays.
    > //
    > // NOTE : Don't use the macro more than once in the same
    > // line of your source as __LINE__ will be same and hence
    > // you would get type-redefinition error.
    > //
    > // And macros are known for side-effects, so be wary of
    > // them or you can just hand-code the comprehensive
    > // typecasting the above macro does without any problem -
    > // you can just ignore __LINE__ macro as well if you code
    > // by hand since you will not deliberately redefine a
    > // struct more than once!
    > #define AssignArraysOfSize(b, a, size) \
    >                         DummyMacro2(b, a, size, __LINE__)
    > int main(void)
    > {
    >     int a[ 10 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    >     int b[ sizeof(a) ];
    >     int i = 0;
    >     printf("Array a : ");
    >     while ( i < 10 )
    >     {
    >           printf("%d ", a[ i ]);
    >           i++;
    >     }
    >     printf("\n");
    >     AssignStaticArrays(b, a); // Once more in the
    >                               // same line -
    >                               // AssignStaticArrays(b, a);
    >                               // - Nope!
    >     i = 0;
    >     printf("Array b : ");
    >     while ( i < 10 )
    >     {
    >           printf("%d ", b[ i ]);
    >           i++;
    >     }
    >     printf("\n");
    >     int z[ sizeof(a) ];
    >     AssignStaticArrays(z, a); // This works as it's on a
    >                               // different line from the
    >                               // previous usage above!
    >     i = 0;
    >     printf("Array z : ");
    >     while ( i < 10 )
    >     {
    >           printf("%d ", z[ i ]);
    >           i++;
    >     }
    >     printf("\n");
    >     int c[ sizeof(a) ];
    >     AssignArraysOfSize(c, a, sizeof(a)); // Same rules
    >                                          // apply to this
    >                                          // macro usage
    >                                          // as well as
    >                                          // above.
    >     i = 0;
    >     printf("Array c : ");
    >     while ( i < 10 )
    >     {
    >           printf("%d ", b[ i ]);
    >           i++;
    >     }
    >     printf("\n");
    >     int d[ sizeof(c) ];
    >     AssignArraysOfSize(d, c, sizeof(c)); // Works as it's
    >                                          // on a different
    >                                          // line.
    >     i = 0;
    >     printf("Array d : ");
    >     while ( i < 10 )
    >     {
    >           printf("%d ", d[ i ]);
    >           i++;
    >     }
    >     printf("\n");
    >     return 0;
    >
    > }
    >
    > </code>


    Typo fix :
    // Why seemingly useless (void *) casting? Well, again
    // to inform the compiler that we are punning types as
    // said earlier and this cast is required for
    // convincing strict-aliasing=1.

    Should be
    // Why seemingly useless (void *) casting? Well, again
    // to inform the compiler that we are *NOT* punning types as
    // said earlier and this cast is required for
    // convincing strict-aliasing=1.
    Myth__Buster, Feb 1, 2013
    #2
    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. Chris
    Replies:
    34
    Views:
    1,492
  2. weston
    Replies:
    1
    Views:
    239
    Richard Cornford
    Sep 22, 2006
  3. Myth__Buster
    Replies:
    13
    Views:
    356
    Anand Hariharan
    Feb 26, 2013
  4. Myth__Buster
    Replies:
    0
    Views:
    237
    Myth__Buster
    Feb 1, 2013
  5. Myth__Buster
    Replies:
    0
    Views:
    232
    Myth__Buster
    Feb 1, 2013
Loading...

Share This Page