Проблема не в кастинге (не требуется, чтобы присвоение было прямым преобразованием в uint8_t
C11 Standard - 6.5.16.1 Простое присвоение (p2) ), проблема - в диапазоне. int x;
- это 32-разрядное целое число со знаком, способное хранить значения в диапазоне -2147483648 to 2147483647
. В отличие от этого uint8_t y;
является 8-разрядным значением без знака, способным содержать значения 0 - 255
.
Вы можете легко присвоить значение x
, которое превышает диапазон y
. Так что же тогда происходит? Если значение x
превышает диапазон y
, значение x
уменьшается по модулю 1 + max_for_type
для соответствия y
C11 Standard - 6.2.5 Типы (p9) Так присвоение эквивалентно y = x % 256;
для значений x
, которые превышают диапазон uint8_t
.
Так, например, x = 25306708;
, тогда когда x
преобразуется в uint8_t
с y = x;
x
, уменьшается по модулю 256
, чтобы он соответствовал y
. (например, y == 84
)
Если вы хотите избежать бесшумного уменьшения значения до значения y
, то вы должны проверить, что значение x
будет соответствовать y
без уменьшения. Вы можете сделать это с помощью простой условной переменной и константы, определенной в stdint.h
, например,
y = x; /* direct assignment, no cast required */
if (0 <= x && x <= UINT8_MAX) /* validate x within the range of uint8_t */
printf ("int x: %d is in range of uint8_t y: %" PRIu8 "\n", x, y);
else
/* handle the error as required */
Составив короткий пример, показывающий поведение, вы можете сделать:
#include <stdio.h>
#include <inttypes.h> /* includes stdint.h */
int main (void) {
int x;
uint8_t y;
fputs ("enter a value: ", stdout);
if (scanf ("%d", &x) != 1) {
fputs ("error: invalid integer value.\n", stderr);
return 1;
}
y = x; /* direct assignment, no cast required */
if (0 <= x && x <= UINT8_MAX) /* validate x within the range of uint8_t */
printf ("int x: %d is in range of uint8_t y: %" PRIu8 "\n", x, y);
else
printf ("x: %d exceeds range of uint8_t, reduced modulo to y: %"
PRIu8 "\n", x, y);
}
Пример использования / Вывод
$ ./bin/intuint8_t
enter a value: 254
int x: 254 is in range of uint8_t y: 254
$ ./bin/intuint8_t
.enter a value: 256
x: 256 exceeds range of uint8_t, reduced modulo to y: 0
$ ./bin/intuint8_t
enter a value: 25306708
x: 25306708 exceeds range of uint8_t, reduced modulo to y: 84
В ответ на:
«Является ли хорошей практикой в C всегда явное приведение переменных»
Нет. Приведение будет маскировать предупреждения, которые сгенерирует компилятор, если то, что вы делаете, включает несовместимые типы. Вы должны приводить только редко и только там, где это явно необходимо, как того требует библиотечный API и т. Д.
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.