I can rotate a word to left or right by a certain amount like this:
#define ROR(x, r) ((x >> r) | (x << (64 - r)))
#define ROL(x, r) ((x << r) | (x >> (64 - r)))
[...]
ROR(var1, 11);
ROL(var1, 11);
How can I do the same but with an entire array of bytes (I mean: all the bits in array sequence)? An array like this:
uint32_t somearray[12] = {
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
};
PS: There is a similar question here, but I need to know how to do it with some amount.
CodePudding user response:
There are 2 problems with the ROR
and ROL
macros:
- the macro assumes that the argument
x
is auint64_t
. - shifting a
uint64_t
by 64 positions has undefined behavior. If the number of shiftsr
can be null, you should modify the expression to avoid shifting by 64. - the macro arguments should be parenthesized in the expansion to avoid precedence issues.
Here is a modified version:
// assuming x is a uint64_t and r in the range 0..63
#define ROR64(x, n) (((x) >> (n)) | ((x) << (63 - (n)) << 1))
#define ROL64(x, n) (((x) << (n)) | ((x) >> (63 - (n)) >> 1))
Note that it is recommended to use inline functions instead of macros to avoid problems with operands with side effects and enforce operand sizes:
// assuming r in the range 0..63
static inline uint64_t ror64(uint64_t x, int n) {
return (x >> n) | (x << (63 - n) << 1);
}
static inline uint64_t rol64(uint64_t x, int n) {
return (x << n) | (x >> (63 - n) >> 1);
}
To rotate a full array of words, it is simpler to use a different array as the source and destination and write a loop:
void ror32_array(uint32_t *dst, const uint32_t *src, size_t size, size_t n) {
size_t dist = n / 32 % size;
int shift = n % 32;
for (size_t i = 0; i < size; i ) {
dst[(i dist) % size] = src[i] >> shift;
}
if (shift) {
for (size_t i = 0; i < size; i ) {
dst[(i dist 1) % size] |= src[i] << (32 - shift);
}
}
}
void rol32_array(uint32_t *dst, const uint32_t *src, size_t size, size_t n) {
size_t dist = n / 32 % size;
int shift = n % 32;
for (size_t i = 0; i < size; i ) {
dst[(i size - dist) % size] = src[i] << shift;
}
if (shift) {
for (size_t i = 0; i < size; i ) {
dst[(i size - dist - 1) % size] |= src[i] >> (32 - shift);
}
}
}
Here is a test program:
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
[...]
void print(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
while (*fmt) {
if (*fmt == '%') {
if (fmt[1] == 'd') {
printf("%d", va_arg(ap, int));
fmt = 2;
continue;
} else
if (fmt[1] == 'p') {
const uint32_t *src = va_arg(ap, uint32_t *);
size_t size = va_arg(ap, size_t);
for (size_t i = 0; i < size; i ) {
printf("lX%c", (long)src[i], " "[i 1 == size]);
}
fmt = 2;
continue;
}
}
putchar(*fmt );
}
va_end(ap);
}
int main() {
uint32_t array[] = { 0, 1, 2, 4, 8, 16 };
size_t size = sizeof(array) / sizeof(*array);
uint32_t dest_array[size];
int i, n, shift[] = { 0, 1, 2, 3, 8, 15, 24, 32, 48, 64, -1 };
print("array = { %p }\n", array, size);
for (i = 0; (n = shift[i]) >= 0; i ) {
ror32_array(dest_array, array, size, n);
memcpy(array, dest_array, sizeof(array));
print("ror(array, %d) = { %p }\n", n, array, size);
}
while ((n = shift[--i]) != 0) {
rol32_array(dest_array, array, size, n);
memcpy(array, dest_array, sizeof(array));
print("rol(array, %d) = { %p }\n", n, array, size);
}
return 0;
}
CodePudding user response:
To rotate all the bits in an array, create a function that takes a size, a pointer to the data, and a shift amount.
void rotate_right(size_t sz, void *a, unsigned shift);
#define ROR_ARRAY(a, sh) rotate_right((sizeof (a)), (a), (sh))
For an array of 32-bit values, the bit shift of the array may be be the same arithmetically as some_32_bit >> sh
due to endian. More advanced use of macros with _Generic
solve solve that.