Всякий раз, когда вы пишете уравнение на C / C ++, типы данных, с которыми вы работаете, оказывают реальное влияние на вывод уравнения.
Каждый тип, как int
, float
и unsigned long
имеет различное поведение, и занимает определенное количество места в памяти для хранения.
int
(в arduino) хранится в 16 битах, половина значений дана для отрицательных чисел, половина - для положительных значений, а одна - для 0. Это дает диапазон -2 ^ 15 (-32,768) до + 2 ^ 15-1 (32 767).
unsigned long
(на Arduino) составляет 32 бита, но ни один не обозначен как отрицательный. его диапазон составляет от 0 до 2 ^ 32-1 (4294967295).
Что за математика? Какой другой тип обработки исключен при работе с миллис?
Суть проблемы в том, что время, когда возвращается миллис, когда-либо превышало 32767, и вы пытались сохранить его в int, arduino не мог этого сделать, потому что не int
может удерживать такое большое число. Тип математики, который является недопустимым, - математика, которая применяется к меньшим типам данных, а не к каким-либо конкретным операциям. Может быть, эти примеры помогут:
int i = 32767;
Serial.println(i);
//No problems here; it fits just fine
32767
i = 32767 + 1;
Serial.println(i);
//Oh no, the value didn't fit
-32768
unsigned long fake_millis = 42000;
i = fake_millis;
Serial.println(i);
//This is an example of millis going past an int
-23536
i = -10;
unsigned int j = i;
Serial.println(j);
//no way to put a negative number in an unsigned value
65526
uint32_t k = fake_millis;
Serial.println(k);
//unsigned long is a uint32_t on arduino; this works great!
42000
То, как это реализовано, действительно гениально; Если вас интересует, откуда взялись эти числа и почему они распространяются так, как они есть, вам следует обратиться к тем же объяснениям представлений чисел в двух дополнениях.
unsigned long
может меняться на разных платформах (например, x86),uint32_t
везде всегда будет 32 беззнаковых бита.32767 + 1
) приводит к неопределенному поведению, что почти всегда плохо . Другие ваши примеры - документированное поведение, на которое вы можете положиться.millis()
возвращает aunsigned long
, которое представляет собой 32-разрядное целое число без знака в Arduino. Затем, когда вы пытаетесь сделать что-то подобноеunsigned int time = millis() - 1000
, вы пытаетесь сохранить это в 16-разрядном целом числе без знакаunsigned int
. 16-разрядное целое число никогда не может содержать 32-разрядное значение.Согласно спецификации C , параграф 6.3.1.3, старшие 16 бит отбрасываются.
Если возможно, сохраняйте
millis()
вывод в aunsigned long
и используйте типы данных только с меньшим количеством битов, когда вы абсолютно уверены, что не потеряете биты.Больше информации о явном приведении в C здесь: https://stackoverflow.com/a/13652624/1544337
источник
uint32_t
который оказываетсяunsigned long
на arduino?unsigned long
.int time = millis() - 1000
), результат аналогичен: старшие 16 бит отбрасываются. На этот раз стандарт C говорит, что результат определяется реализацией, а поведение указано в документации gcc по определяемому реализацией поведению целых чисел (четвертая точка).Если вы хотите что-то сделать с помощью millis (), просто не забудьте инициализировать переменную с типом "uint32_t"
Так что сделайте что-то вроде «uint32_t last_millis», где вы будете хранить выходные данные функции «millis ()».
В противном случае, как говорили другие, оно превысит 31000, что произойдет довольно быстро.
источник