Что за цирк с типом данных int?

А надо бы. Вас не смутило, что условие цикла выглядит как 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. Сейчас вернул назад в стандартную логику, но её (стандартной логики) пока всё равно не наблюдается (см. скриншот):

Этот код работает? Только не говорите, что нет, я его проверил :wink:

О да! Вот так заработало! Спасибо вам.

Значит получается, если я на платформе Ардуино хочу использовать весь диапазон значений 2^n бит, мне надо брать следующий тип данных? Типа хочу отсчитать 1 байт (от 0 до 255) - беру int 2 байта (от 0 до 64к), а если понадобится отсчитать int 2 байта, то надо брать long 4 байта (от 0 до 4г)?

Условие должно вмещаться в выбранную размерность с запасом. Будьте уверены, даже если сериал отображал бы все правильно, цикл у вас все равно был бы бесконечным

Да и с int32_t тоже работает. :slightly_smiling_face: Размерность только другая.

Кнопочку Решено нажмите

Я пока про этот тип данных ещё не прочитал. А если я вас правильно понимаю, в работе функции 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");
}