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 not 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 not 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>