Всем большое спасибо за направление на путь истинный!
-0d32768 у вас что калькулятора нет ???
Я вам об этом сразу написал ! - Что за цирк с типом данных int? - #5 от пользователя Komandir
Решено то решено, но почему так Сериал с циклом с интом ведёт, вопрос то остался. Возможно пофиксят.
А не так просто посчитать это. Попробуйте сами встроенный калькулятор Windows . Я тоже удивился, когда пытался посчитать это для примера. Калькулятор автоматически расширяет тип данных с int на long :).
Удобнее задавать самому тип данных:
int8_t - 1 байт знаковый
uint8_t - 1 байт без знаковый
int16_t
uint16_t
32
64
Принцып такой.
Вы не слушаете, что Вам говорят. Глюк существует в Вашей голове. Нигде больше никакого глюка нет. Или Вы подумали, что я пошутил, когда это говорил? Нет, не пошутил. И чем быстрее Вы это поймёте, тем быстрее добьётесь прогресса в программировании.
Не уверен, что я понял эту фразу, но замечу, на С++ у Вас тоже получился бред сивой кобылы. Разве нет?
Такого вопроса Вы не задавали. Я отвечал на вопрос почему условие прекращения цикла не сработало.
Вы поняли ответ? Теперь знаете и не считаете это глюком? Или надо ещё объяснять? Пока Вы не поймёте это, к следующему вопросу я переходить не буду.
Это не баг. Так и задумано.
Да, ладно, мы на старом форуме это уже обсуждали, причём не раз. Вот как выглядит соответствующая функция класса Print
size_t Print::print(int n, int base)
{
return print((long) n, base);
}
Вопросы остались?
Про Сериал принт вопросов нет.
А вот с циклом все равно не понимаю.
По моей логике в этом цикле:
for (int i = 0; i <= 32767; i++){
Значения i
должны идти сначала от 0 до 32767, потом перейти в -32768 и потом через отрицательные значения подняться обратно до нуля.
Если оператор принт преобразует число в лонг, то на мой взгляд печать должна выглядеть так : 0…32767 → 65536…32768 → 0…32767
Я не понимаю, как числа уходят выше 65536. Ведь то, что происходит внутри принт - не затрагивает переменную цикла i ?
Да, нет, вполне логично. Более, чем. Я эту логику как-то уже объяснял, но что-то не могу найти на старом форуме. Если не найду, может снова напишу, но пока поищу
если вы пр логику оператора принт - то не надо.
Лучше обьясните как значение переменной цикла уходят выше 0xffff
Видимо потому, что i больше нигде не используется, кроме как в print, вот и приводится к long
Вон в протеусе с отключенной оптимизацией все корректно показывает
Хорошо, только завтра. Букв много, а сегодня я уже не могу, биполярный режим ADC 85-ой тиньки все соки из меня выпил.
это даже хорошо.
Я пока поэксперементирую, не люблю получать ответы на блюде - я их забываю через полдня
А увлекательно :))))
Для начала залил в нано код ТС. Результат как у него - значение в мониторе растет, проскакивает 32767, продолжает дальше… проскакивает через 65536… и не останавливается.
Ладно думаю, посмотрим что там в HEX - заменил строчку принта на
Serial.println(i, HEX);
Результат в момент пересечения границы 16 бит выглядит так
FFFE
FFFF
10000
10001
10002
То есть счетчик переполняет 2 байта и вылезает в третий.
Я решил выяснить - это цикл for косячит - счетчик переполняется и залезает в соседний байт - или это опять шутки Serial.print.
Для этого я решил скопировать в отдельный буфер три байта по адресу переменной i
и напечатать их отдельно:
uint8_t buf[3] = {0};
for (int i = 0; i <= 32767; i++){
memcpy(buf, &i, 3);
Serial.print(buf[0], HEX);
Serial.print(" ");
Serial.print(buf[1], HEX);
Serial.print(" ");
Serial.print(buf[2], HEX);
Serial.print(" ");
Serial.println(i);
}
Ага, думаю, ща я тебя поймаю!
И что вы думаете?
0 0 0 0
1 0 0 1
2 0 0 2
3 0 0 3
....
FB 7F 0 32763
FC 7F 0 32764
FD 7F 0 32765
FE 7F 0 32766
FF 7F 0 32767
0 80 0 -32768
1 80 0 -32767
2 80 0 -32766
3 80 0 -32765
4 80 0 -32764
5 80 0 -32763
...
F9 FF 0 -7
FA FF 0 -6
FB FF 0 -5
FC FF 0 -4
FD FF 0 -3
FE FF 0 -2
FF FF 0 -1
0 0 0 0
1 0 0 1
2 0 0 2
3 0 0 3
4 0 0 4
5 0 0 5
Компилятор не дал себя поймать. За пределы двух байтов, отведенных под переменную - он не залезает. И самое удивительное, что и Serial.print теперь печатает правильно.
Хотя, казалось бы - я на переменную i своим кодом никак не влияю. Всего лишь копирую ее значение. Прямо принцип неопределенности в действии - невозможно узнать координату электрона, не переместив его
Причину такого поведения, видимо, правильно указал @v258 в сообщении #53. Но, по-моему, это типичный баг - поскольку результат исполнения программы оказывается явно неверным
Хотя с другой стороны - исходный цикл написан так, что вызывает переполнение разрядности переменной итератора. В таких условиях никто гарантии правильной работы кода не даст. Типичный пример “неопределенного поведения”, видимо.
Хорошо, что до битшифта инта не добрался. Там тоже можно спиться.
Если i объявить глобальной , то все работает правильно. Что то происходит если переменная локальная.
Или статической прям в цикле, то тоже правильно работает.
Статическая - такая же глобальная (не на стеке, не в регистрах), просто с ограниченной областью видимости.
Посмотрел в ASM - из за оптимизации (для последующего Serial.print((long)i) )под локальную переменную отводится на кадр на стеке, а 4 регистра и дальше всё проходит как с LONG. Компилятор видит что цикл бесконечный и вывод “End” в окончательном коде вообще отсутствует…
Стоит запросить адрес переменной i и фокус с регистрами у оптимизатора не выходит и всё начинает работать:
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("Start");
for (int i = 32000; i <= 32767; i++) {
Serial.print((int)&i, HEX);
Serial.print(" ");
Serial.println(i);
}
Serial.println("End"); //никогда не выполнится и в итоговый код не попадает !
}