M
Myth__Buster
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>
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>