Правильный способ объявления макроса препроцессора двоичного вращения - PullRequest
0 голосов
/ 02 октября 2018

Я хотел бы создать макросы для бинарных вращений.Моя цель состояла в том, чтобы сделать эти макросы универсальными для типов операндов uint32_t и uint64_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))))

Я знаю, что компилятор жалуется на возможное несоответствие между типами X и N.Но предупреждения выдаются, даже когда я разыграю X и N:

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

Что я могу сделать, чтобы избавиться от этих предупреждений правильным способом?

Ответы [ 3 ]

0 голосов
/ 02 октября 2018

Вы получаете предупреждение только тогда, когда второй аргумент равен нулю.Так что просто ничего не делайте, если N == 0:

#define ROTL(X, N)  ((N) == 0 ? (X) : (((X) << (N)) | ((X) >> (8 * sizeof(X) - (N)))))
0 голосов
/ 02 октября 2018

Вы получаете некоторые проблемы, когда второй аргумент равен нулю или больше, чем число битов первого аргумента.Вы можете попробовать использовать модуль, чтобы избавиться от этой проблемы.Похоже, это работает на следующем простом примере:

#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 из limits.h и UINT32_C и PRIX32 из inttypes.h.Вы можете настроить ROTR, чтобы сделать то же самое.

0 голосов
/ 02 октября 2018

приведите сдвинутый операнд к максимально возможной ширине.

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