целочисленное переполнение в константном выражении

Хотя это отлично компилируется в 64-битной версии Linux с gcc:

#define CONST_1 255
#define CONST_2 255

#define CONST_PROD ((CONST_1) * (CONST_2))

он выдает предупреждение о переполнении на avr-gcc (8 бит):

constants.c:13:31: warning: integer overflow in expression [-Woverflow]
 #define CONST_PROD ((CONST_1) * (CONST_2))
                               ^

что достаточно справедливо, поскольку результат слишком велик для 16-битного целого числа со знаком.

Предупреждение исчезает при определении констант(ы) следующим образом:

#define CONST_1 255U

или добавив приведение:

#define CONST_PROD ((uint16_t)(CONST_1) * (CONST_2))

Я думаю, что на самом деле оба делают то же самое, но один из способов предпочтительнее другого?


person Torsten Römer    schedule 29.03.2016    source источник
comment
255U или 255UL, безусловно, самое простое решение. Я думаю, вам следует проверить, используете ли вы константы в любом контексте, где ожидается подписанное поведение.   -  person M.M    schedule 30.03.2016
comment
Ознакомьтесь с гарантированными диапазонами типов целых чисел. Переполнение целого числа со знаком всегда является неопределенным поведением (также известным как большая проблема или катастрофа). Вам повезло, что компилятор поймал его на константах. Скорее всего, не будет при использовании переменных, поэтому будьте очень осторожны! И вы должны избегать бросков, где это возможно.   -  person too honest for this site    schedule 30.03.2016
comment
Кроме того, рассмотрите возможность использования стандартного включаемого файла <limits.h>.   -  person Jens    schedule 30.03.2016


Ответы (1)


Избегайте приведения типов, которые могут неожиданно сузить значение.

Альтернативы - лучше всего зависит от многих вещей. В общем, если число должно быть беззнаковым, добавьте u или используйте UINTN_C()

 // u or U the same
 #define CONST_1 255U
 #define CONST_1 255u

 // 1u* to bring about unsigned math.  () around `CONST_1` shouldn't be necessary.
 #define CONST_PROD (1u*CONST_1 * CONST_2)

 // Macros for minimum-width integer constants
 #include <stdint.h>
 // UINT16_C() makes the constant type uint_least16_t
 #define CONST_PROD (UINT16_C(CONST_1) * UINT16_C(CONST_2))

OTOH, если значение должно состоять из точных N битов и не иметь другой ширины,

 #define CONST16_MASK_MIDDLE_BITS  ((uint16_t) 0x00FFFF00u)

Я не вижу большой ценности в UL. Если вы хотите, чтобы константа была широкого типа, выберите самый широкий.

 #define CONST_1 255ULL
 // or 
 #define CONST_1 ((uintmax_t)255u)
person chux - Reinstate Monica    schedule 30.03.2016