А надо бы. Вас не смутило, что условие цикла выглядит как i <= 255 ?
Вы издеваетесь? Почему 32768?
Да без проблем
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while(!Serial);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("Start");
for (long i = 0; i <= 32767; i++) {
Serial.println(i);
}
Serial.println("End");
}
Теоретически вы абсолютно правы. Конечно начинал я с 32767. Просто на экране остался след от эксперимента, когда я, пытаясь понять Ардуино, подумал “а вдруг там как-то всё не так, как в обычных компьютерах на базе процессоров Intel?”, и поменял 32767 на 32768. Сейчас вернул назад в стандартную логику, но её (стандартной логики) пока всё равно не наблюдается (см. скриншот):
Этот код работает? Только не говорите, что нет, я его проверил
О да! Вот так заработало! Спасибо вам.
Значит получается, если я на платформе Ардуино хочу использовать весь диапазон значений 2^n бит, мне надо брать следующий тип данных? Типа хочу отсчитать 1 байт (от 0 до 255) - беру int 2 байта (от 0 до 64к), а если понадобится отсчитать int 2 байта, то надо брать long 4 байта (от 0 до 4г)?
Условие должно вмещаться в выбранную размерность с запасом. Будьте уверены, даже если сериал отображал бы все правильно, цикл у вас все равно был бы бесконечным
Да и с int32_t тоже работает. Размерность только другая.
Кнопочку Решено нажмите
Я пока про этот тип данных ещё не прочитал. А если я вас правильно понимаю, в работе функции Serial.println() всё-таки есть баг?
Похоже да. Может более опытные товарищи ещё объяснят.
Это Вы ещё до неявных преобразований типов в С++ не дошли, вот там “веселье”.
Вопрос хороший, как раз таким как я начинающим разбираться.
С “цирком” , конечно, перебор.
В Proteus всё правильно выводится. Код из первого сообщения
Там по умолчанию оптимизация отключена - O0.
Знаю, пробовал-О3 -не влияет
P.S. компилятор Arduino AVR
Не надо следующий тип выбирать.
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while(!Serial);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("Start");
for (int i = 0-1; i <= 32767-1; i++) {
Serial.println(i+1);
}
Serial.println("End");
}
Обход бага Сериал?
В железе не тестил …
В общем, стало всё понятно. Это немного непривычно после работы с языками, где нет такого жёсткого контроля типов данных…
Объясняю сам себе. По условию примера переменная i счетчика должна тикать от 0d0 (оно же 0x0, оно же 0b0000000000000000) до 0d32767 (0x7FFF, 0b0111111111111111). В последней итерации получается следующее неравенство:
32767 <= 32767
Это условие выполняется, поэтому цикл делает свою работу, а в конце происходит очередное увеличение счетчика, которое выполняется следующим арифметическим действием:
0b0111111111111111+
0b0000000000000001
И что у нас должно получиться в результате такого сложения? В этом месте у меня крышу и сорвало. По моей мысли, при попытке выполнить такое сложение старший бит не должен был меняться, а вместо этого должен быть взведен флаг CF (carry flag), который мы анализируем при необходимости. Ардуино же, видимо, этого не делает, и вместо результата
0b0111111111111111+
0b0000000000000001=
0b0000000000000000, CF=1
делает так:
0b0111111111111111+
0b0000000000000001=
0b1000000000000000
И вот тут-то дьявол начинает крыться в деталях! Как теперь трактовать полученный результат?! Если я объявляю тип данных как unsigned int (беззнаковое двухбайтовое число с диапазоном от 0 до 0d65535), то оно будет расцениваться как положительное +0d32768. Но я объявил его как тип int (двухбайтовое число СО ЗНАКОМ)! Поэтому оно трактуется как отрицательное -0d32767. Вот так, “лёгким движением руки” (указанием неверного типа данных int для счетчика цикла i) число +32к превращается в -32к, и конечно, с точки зрения банальной математики неравенство
-0d32767 <= +0d32767
выполняется!
Цикл продолжит свою работу, при следующей итерации математика даст такой результат
-0d32767+
** 0d00001=**
-0d32766,
неравенство -32766 <= 32767 снова выполнится, и цикл поедет дальше. Он уже никогда не выйдет из него! Чтобы избежать этого глюка, мне надо было правильно задать тип данных. Либо это должно быть unsigned int, либо long:
И в том, и в другом случае обработка старшего бита числа 0b1000000000000000 происходит корректно, и я получаю ту логику, которую ожидаю получить.
Вывод прост - правильно выбирайте типы данных для своих данных, и да пребудет с вами сила!
P.S. Ну а баг функции Serial.println(), я надеюсь, починят в следующих релизах.
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while(!Serial);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("Start");
int i=0;
do
Serial.println(i);
while (i++<32767);
Serial.println("End");
}