recently, i was curious on how qsort()
sorts without passing specific type, thus i'm trying to reverse an array without knowing / caring it's type.
i was told you can do pointer arithmetic if you cast void *
into a char *
.
void swap(void *a, void *b)
{
char tmp = *(char *)a;
*(char *)a = *(char *)b;
*(char *)b = tmp;
}
the function swap()
works well with type int
& char
but not with float
nor double
.
i don't know why this is the case, but i saw an implementation of swapping with memcpy()
, with that, i implented so:
void __swap(void *a, void *b, size_t size)
{
char buf[size];
memcpy(buf, a, size);
memcpy(a, b, size);
memcpy(b, buf, size);
}
reverse function implementation using swap()
:
void arr_reverse(void *arr, size_t size, size_t len)
{
for (size_t i = 0, j = len - 1; i < len / 2; i++, j--)
swap(arr + (i * size), arr + (j * size));
}
reverse function implementation using __swap()
:
void arr_reverse(void *arr, size_t size, size_t len)
{
for (size_t i = 0, j = len - 1; i < len / 2; i++, j--)
__swap(arr + (i * size), arr + (j * size), size);
}
__swap()
works greatly, but i don't know why this is the case, so the question is, what's the difference between swap()
and __swap()
?
i'm assuming there's something to do with type sizes
void *
arithmetics is an undefined behaviour. It is a GCC extension and it is not allowed by the C standard.
__swap
, and swap
are doing something completely different. The first is swapping whole chunks
of memory of the size
len. Latter one is swapping only first chars leaving the rest untouched for longer types (like double or float)
void swap(void *a, void *b)
{
char tmp = *(char *)a;
*(char *)a = *(char *)b;
*(char *)b = tmp;
}
void __swap(void *a, void *b, size_t size)
{
char buf[size];
memcpy(buf, a, size);
memcpy(a, b, size);
memcpy(b, buf, size);
}
void invalid_arr_reverse(void *vp, size_t size, size_t len)
{
unsigned char *arr = vp;
for (size_t i = 0, j = len - 1; i < len / 2; i++, j--)
swap(arr + (i * size), arr + (j * size));
}
void arr_reverse(void *vp, size_t size, size_t len)
{
unsigned char *arr = vp;
for (size_t i = 0, j = len - 1; i < len / 2; i++, j--)
__swap(arr + (i * size), arr + (j * size), size);
}
void printarr(uint32_t *arr, size_t size )
{
while(size--) printf("0x%08x\n" ,(unsigned)*arr++);
}
int main(void)
{
uint32_t arr[4] = {0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff};
uint32_t arr1[4] = {0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff};
invalid_arr_reverse(arr, 4, 4);
printarr(arr, 4);
arr_reverse(arr1, 4, 4);
printarr(arr1, 4);
}
https://godbolt.org/z/z1sYrPj6G
Byte swapping function has to be written different way:
void arr_reverse(void *vp, size_t size, size_t len)
{
unsigned char *arr = vp;
for (size_t i = 0; i < len / 2; i++)
for(size_t j = 0; j < size; j++)
swap(arr + (i * size) + j, arr + (len - i -1) * size + j);
}