C语言 如何将字节数组中的所有位向左/向右旋转一定的量

4si2a6ki  于 2023-01-20  发布在  其他
关注(0)|答案(2)|浏览(140)

我可以像这样将一个单词左右旋转一定的Angular :

#define ROR(x, r) ((x >> r) | (x << (64 - r)))
#define ROL(x, r) ((x << r) | (x >> (64 - r)))

[...]

ROR(var1, 11);
ROL(var1, 11);

我怎么能做同样的事情,但对一个完整的字节数组(我的意思是:数组序列中的所有位)?一个如下的数组:

uint32_t somearray[12] = {
    0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
    0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
};

PS:有一个similar question here,但我需要知道如何做一些数额。

lsmepo6l

lsmepo6l1#

RORROL宏有两个问题:

  • 宏假设自变量xuint64_t
  • uint64_t移位64位具有未定义的行为。如果r的移位数可以为空,则应修改表达式以避免移位64位。
  • 宏参数应该在展开中用括号括起来以避免优先级问题。

以下是修改后的版本:

// 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))

请注意,建议使用内联函数而不是宏,以避免操作数产生副作用并强制操作数大小的问题:

// 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);
}

要旋转一个完整的单词数组,使用不同的数组作为源和目标并编写一个循环会更简单:

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);
        }
    }
}

下面是一个测试程序:

#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("%08lX%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;
}
rta7y2nd

rta7y2nd2#

要循环移位 array 中的所有位,请创建一个函数,该函数接受大小、指向数据的指针和移位量。

void rotate_right(size_t sz, void *a, unsigned shift);
#define ROR_ARRAY(a, sh) rotate_right((sizeof (a)), (a), (sh))

对于一个32位值的数组,由于字节序的原因,数组的位移位在算术上可能与some_32_bit >> sh相同。更高级的_Generic求解宏的使用解决了这个问题。

相关问题