по сути, функция подкачки заключается в обмене двух блоков памяти. с двумя адресами и размером блока в байтах мы можем поменять местами указатели, целые числа, числа, массивы, структуры, ...
указатель состоит из трех частей, например мы можем разбить short* p
на три части
- адрес: недействительный * р
- размер: читая два байта в
void*p
, мы получаем короткое целое число.
- использование: например выведите короткое целое число с помощью
%hu
Используя первые две части, мы сможем построить общую функцию подкачки:
#include<stdint.h>
#ifdef _WIN32
#define alloca _alloca
#else
#include <alloca.h>
#endif
void gswap(void * const a, void * const b, int const sz) {
// for most case, 8 bytes will be sufficient.
int64_t tmp; // equivalent to char tmp[8];
void * p;
bool needfree = false;
if (sz > sizeof(int64_t)) {
// if sz exceed 8 bytes, we allocate memory in stack with little cost.
p = alloca(sz);
if (p == NULL) {
// if sz is too large to fit in stack, we fall back to use heap.
p = malloc(sz);
//assert(p != NULL, "not enough memory");
needfree = true;
}
}
else {
p = &tmp;
}
memcpy(p, b, sz);
memcpy(b, a, sz);
memcpy(a, p, sz);
if (needfree) {
free(p);
}
}
например:.
{// swap int
int a = 3;
int b = 4;
printf("%d,%d\n", a, b);//3,4
gswap(&a, &b, sizeof(int));
printf("%d,%d\n", a, b);//4,3
}
{// swap int64
int64_t a = 3;
int64_t b = 4;
printf("%lld,%lld\n", a, b);//3,4
gswap(&a, &b, sizeof(int64_t));
printf("%lld,%lld\n", a, b);//4,3
}
{// swap arrays
int64_t a[2] = { 3,4 };
int64_t b[2] = { 5,6 };
printf("%lld,%lld,%lld,%lld\n", a[0], a[1], b[0], b[1]);//3,4,5,6
gswap(&a, &b, sizeof(a));
printf("%lld,%lld,%lld,%lld\n", a[0], a[1], b[0], b[1]);//5,6,3,4
}
{// swap arrays
double a[2] = { 3.,4. };
double b[2] = { 5.,6. };
printf("%lf,%lf,%lf,%lf\n", a[0], a[1], b[0], b[1]);//3.000000, 4.000000, 5.000000, 6.000000
arrswap(&a, &b, sizeof(a));
printf("%lf,%lf,%lf,%lf\n", a[0], a[1], b[0], b[1]);//5.000000, 6.000000, 3.000000, 4.000000
}