声明二进制旋转预处理器宏的正确方法

时间:2018-10-02 13:08:07

标签: c gcc macros binary bit-manipulation

我想为二进制旋转创建宏。 我的目标是使这些宏对于uint32_tuint64_t操作数类型都是通用的。

我来到了这个实现:

#define ROTL(X, N)  (((X) << (N)) | ((X) >> (8 * sizeof(X) - (N))))
#define ROTR(X, N)  (((X) >> (N)) | ((X) << (8 * sizeof(X) - (N))))

这些宏可以正常工作,但是gcc编译器在编译期间会发出警告:

warning: right shift count >= width of type [enabled by default]
#define ROTL(X, N)  (((X) << (N)) | ((X) >> (8 * sizeof(X) - (N))))

warning: left shift count >= width of type [enabled by default]
#define ROTL(X, N)  (((X) << (N)) | ((X) >> (8 * sizeof(X) - (N))))

我知道编译器抱怨XN类型之间可能不匹配。但是即使我同时投射XN,也会产生警告:

ROTL((uint32_t)0xdeadbeef, (uint32_t)0U);

我该怎么做才能以正确的方式消除这些警告?

3 个答案:

答案 0 :(得分:3)

当第二个参数为零或大于第一个参数的位数时,您会遇到一些问题。您可以尝试使用该模块摆脱此问题。通过以下简单示例,这似乎可行:

#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <limits.h>

#define ROTL(X, N) \
    (((X) << ((N) % (CHAR_BIT * sizeof(X)))) | \
     ((X) >> ((CHAR_BIT * sizeof(X) - (N)) % (CHAR_BIT * sizeof(X)))))

int main() {
    for (int i = 0; i < 100; i++) {
        uint32_t a = ROTL(UINT32_C(0xdeadbeef), i);
        printf("%d\t%"PRIX32"\n", i, a);
    }
    return 0;
}

我使用了CHAR_BIT的{​​{1}}和limits.h的{​​{1}}和UINT32_C。您可以PRIX32自己进行调整以执行相同的操作。

答案 1 :(得分:2)

仅当第二个参数为零时,您才收到警告。因此,如果N == 0

#define ROTL(X, N)  ((N) == 0 ? (X) : (((X) << (N)) | ((X) >> (8 * sizeof(X) - (N)))))

答案 2 :(得分:0)

将移位后的操作数投射到最大可能宽度。

#define ROTL(X, N)  (((uint64_t)(X) << (N)) | ((uint64_t)(X) >> (8 * sizeof(X) - (N))))