Целочисленные константы 1U
имеют тип unsigned int
. Типом результата операции сдвига является тип его (повышенного) левого операнда, в этом случае unsigned int
.
Выполнение сдвигов битов для типов без знака является правильным способом, но после завершения сдвига вам необходимопреобразовать обратно в предполагаемый подписанный тип. В противном случае преобразование в int64_t
не «расширит знак» числа, так как компилятор видит неподписанный тип.
Обратите внимание, что -SCALEFACTOR_16
подозрительно по той же причине, но на самом деле это не так. что угодно, потому что операнд унарного минуса не подписан. При правильном преобразовании из неподписанного типа в подписанный компилятор будет обрабатывать знак автоматически, поэтому нет необходимости в том, что -
.
SCALEFACTOR_16
также получит ошибку, вам нужно заключить параметр макроса в скобки.
Решение:
#define SCALEFACTOR_16(N) ( 1U << (N) )
#define Q_MAX16 ( (int16_t)(SCALEFACTOR_16(16-1) - 1U) )
#define Q_MIN16 ( (int16_t)(SCALEFACTOR_16(16-1) ) )
Вы также можете легко сделать этот макрос довольно типичным:
#define SCALEFACTOR(N) ( 1U << (N) )
#define Q_MAX(N) ( (int##N##_t)( SCALEFACTOR(N-1) - 1U ) )
#define Q_MIN(N) ( (int##N##_t)( SCALEFACTOR(N-1) ) )
Полный пример:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#define SCALEFACTOR(N) ( 1U << (N) )
#define Q_MAX(N) ( (int##N##_t)( SCALEFACTOR(N-1) - 1U ) )
#define Q_MIN(N) ( (int##N##_t)( -SCALEFACTOR(N-1) ) )
int main (void)
{
int64_t x;
x = Q_MIN(16);
printf("%.16"PRIx64 " %"PRIi64 "\n", x, x);
x = Q_MIN(32);
printf("%.16"PRIx64 " %"PRIi64 "\n", x, x);
}