У меня есть вопрос относительно неявного преобразования uint8_t
и uint16_t
с помощью Arduino IDE 1.8.2 (gcc 4.9.2.). Аппаратное обеспечение стандартное Arduino (ATMega328p).
Я написал кусок кода, используя uint8_t
, а потом решил переключиться на uint16_t
. (Должен был предвидеть это...)
Однако для неявных преобразований они ведут себя несколько иначе, что вызывало ошибки в программе.
Минимальный рабочий пример следующий:
void setup()
{
uint8_t x = 15;
uint8_t y = 5;
float myF = y-x;
Serial.begin(74880);
Serial.println(myF);
}
На моей последовательной консоли будет напечатано -10.00.
Это хорошо, чего я и ожидал.
Однако, если я изменю x
(или x
и y
) на uint16_t
, результат будет 65526,00! Если я изменю myF
с float на int, я снова получу -10. (Я никогда не меняю значения)
Поскольку я сохраняю результат в типе данных со знаком, я предполагаю, что компилятор понимает возможность отрицательных значений и «правильно обрабатывает ситуацию» (сохраняет знак, как в случае с int) или печатает предупреждение, если это не так. не доволен несоответствием типов данных. Однако даже с уровнем предупреждения, установленным на «все», он никогда не показывал предупреждение. Поэтому я предполагаю, что компилятор знает, как справиться с ситуацией, не теряя знак/данные.
Кроме того, поскольку он работает с int в качестве целевого типа данных, меня удивляет, что он не работает с большим числом с плавающей запятой.
Я проверил ситуацию на своей системе x86 - gcc 4.7.3 сохраняет знак. Однако в мире 8-битных микроконтроллеров AVR могут применяться другие правила/условия. (?)
Так что же там происходит? Может быть, кто-то с большим знанием компилятора может помочь здесь..
(Я знаю, что мог бы избежать этой ситуации, явно приведя, но поэтому я должен был знать об этой ловушке.
Итак, я хотел бы знать чем именно это вызвано, так как действительно было неожиданностью при переключении с uint8_t
на uint16_t
..)
Я прочитал это в соответствии с правила преобразования целых чисел "целочисленные типы, меньшие, чем int, преобразуются в int, когда над ними выполняется операция". Я предполагаю, что avr-gcc следует целочисленным акциям. (?) Итак, я понимаю, что фактическое вычисление обычно выполняется с целым числом, а затем преобразуется в целевой тип данных (в данном случае с плавающей запятой). Проблема в том, что uint16_t
имеет такой же размер, но не меньше, чем 16-битный int AVR, и поэтому uint16_t
не может быть повышен? Если да, то почему он работает с int в качестве целевого типа?
И почему он работает с целочисленной целевой переменной, но не с 4-байтовым числом с плавающей запятой? А почему не предупреждает?
int
16-битное, тоuint16_t
не меньше. Оба операнда имеют одинаковый тип, поэтому вычитание выполняется с помощьюunsigned
, а значение переносится четко определенным образом. - person Weather Vane   schedule 13.06.2018float
, и компилятор ничего не реализует. Результат присваиваетсяfloat
потом. Вы должны были бы привести один операнд кfloat
перед вычислением, чтобы сделатьfloat
соображением. - person Weather Vane   schedule 13.06.2018