Как собрать данный макрос?
Мне нужно собрать такой макрос, который будет принимать массив бежать по каждому его элементу и переставлять биты внутри этого элемента таким образом, что самый правый байт становиться на место самого левого, а левый на место правого, потом дальше следующий байт справа на место следующего слева, а левый с правым.
Я написал вот такой макрос
#define reverse(arr, size)({\
int i; \
int tmp;\
int inside;\
int tmp_size;\
char left;\
char right\
for(i = 0; i < (size); i++)\
tmp = (arr)[i]\
tmp_size = sizeof(tmp)\
for(inside = 0; inside < tmp_size; inside++)\
left = tmp[inside];\
right = tmp[tmp_size - inside]\
tmp[inside] = right\
tmp[tmp_size - inside] = left})\
Во первых я не уверен, что он написан правильно, так как не могу проверить из за ошибки которую получаю когда пробую его вызвать
int main() {
int arr_size = 8;
int arr[arr_size];
int arr_result[arr_size];
int idx;
for (idx = 0; idx < arr_size; ++idx) {
arr[idx] = idx;
}
reverse(arr, arr_size);
return 0;
}
====================[ Build | test_c | Debug ]==================================
/Applications/CLion.app/Contents/bin/cmake/mac/bin/cmake --build /Users/aleksey/CLionProjects/test_c/cmake-build-debug --target test_c -- -j 4
Scanning dependencies of target test_c
[ 50%] Building C object CMakeFiles/test_c.dir/main.c.o
/Users/aleksey/CLionProjects/test_c/main.c:39:5: error: expected ';' at end of declaration
reverse(arr, arr_size);
^
/Users/aleksey/CLionProjects/test_c/main.c:18:9: note: expanded from macro 'reverse'
for(i = 0; i < size; i++)\
^
/Users/aleksey/CLionProjects/test_c/main.c:39:5: error: subscripted value is not an array, pointer, or vector
reverse(arr, arr_size);
^~~~~~~~~~~~~~~~~~~~~~
/Users/aleksey/CLionProjects/test_c/main.c:23:28: note: expanded from macro 'reverse'
right = tmp[tmp_size - inside]\
~~~^~~~~~~~~~~~~~~~~~
2 errors generated.
Что делаю не так?
P.S. По заданию нужно выполнить это как макрос
Ответы (1 шт):
Попробуйте. По идее должно работать для всех размеров целых чисел.
#define GET_BIT(v, bno) (((v) >> (bno)) & 1)
#define SET_BIT(v, bno, bv) ( ((v) & ~(1ULL << (bno))) \
| (((unsigned long long)(bv) & 1) << (bno)))
#define REV_BITS(x) ({__typeof__(x) u = x; \
for (int left = sizeof(x) * CHAR_BIT - 1, right = 0; \
left > right; left--, right++) { \
int lbv = GET_BIT(u, left), rbv = GET_BIT(u, right); \
u = SET_BIT(u, right, lbv); u = SET_BIT(u, left, rbv); \
} u;})
#define REVERSE_BITS(array, n) ({ \
for (int i = 0; i < n; i++) \
(array)[i] = REV_BITS((array)[i]); })
Константа CHAR_BIT определена в <limits.h>. Это количество бит в байте (точнее в типе char) (ага, бывают архитектуры, например TMS, где это число может быть не равно всем привычным восьми).
На всякий случай для перестановки байт тоже написал.
#define REVERSE_BYTES(array, n) ({ \
for (int i = 0; i < n; i++) \
REV_BYTES((array) + i); })
#define REV_BYTES(a) ({ unsigned char *p = (unsigned char *)(a); \
int r = sizeof(*(a)) - 1; \
for (int l = 0; l < r; l++, r--) { \
unsigned char c = p[l]; p[l] = p[r]; p[r] = c; \
}})
Собственно, макрос REV_BITS можно сделать более оптимальным, определив макрос, скажем, SET_2BITS(v, bno1, bv1, bno2, bv2) аналогичный SET_BIT. Там надо сразу сбрасывать в ноль 2 бита (v) & ~((1ULL << bno1) | (1ULL << bno2)) и устанавливать их в нужные значения.
Но это уж вы сами можете потренироваться.
Программка для тестирования что-то вроде
int
main(int ac, char *av[])
{
unsigned short arr[4] = {0, -1, 1, 0xff55aa01};
long z = SET_BIT(0, 7, 1);
printf("z 7 %016lx\n", z);
z = SET_BIT(0x70abcdef, 31, 1);
printf("z 31 %016lx\n", z);
REVERSE_BITS(arr, 4);
for (int i = 0; i < 4; i++)
printf("%016x\n", arr[i]);
REVERSE_BYTES(arr + 3, 1);
printf("%016x\n", arr[3]);
return puts("End") == EOF;
}
Меняете на разные типы и т.п., запускаете и смотрите.