Странное поведение счетчика int в цикле for

smailik
Offline
Зарегистрирован: 08.04.2021

Доброго всем дня.

В ардуино я новичок. А вот в программировании вроде нет.
И тут поведение одного скетча поставило меня в тупик.
Надо было слить дамп с EEPROM 256Кбит, соответственно адреса с 0 до 32767.
Для проверки сначала решил последние 700 ячеек вывести в Serial.
И увидел, что переменная типа int принимает значения больше 32767 и даже 65535 (unsigned int).
Вот такой примитивный код (редуцирован для нагядности) 

void setup()
{
  Serial.begin(115200); // Initialize the serial line
  
  Serial.println("START");
  for (int i = 32000; i >= 0 && i <= 32767; i++)
  {
    Serial.println(i);
  }
  Serial.println("DONE");

}

void loop()
{
}

Кто может объяснить, почему вывод в serial не заканчивается на 32767 ?

Я досмотрел до значений > 300 000

 

 

b707
Offline
Зарегистрирован: 26.05.2017

smailik пишет:

Вот такой примитивный код (редуцирован для нагядности)

приведенный вами код печатает строго от 32000 до 32767.

давайте показывайте, что вы там "редуцировали" для наглядности. Думаю. именно в той части собака и зарыта. Новички часто выкидывают из кода самые значимые части. Так что раз не понимаете. как код работает - значит и сокращать не умеете. Показывайте целиком.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Так, мысли в слух:

Если в условии цикла вместо "&&" поставить "||", то оно выполнялось бы всегда, но должно ж было бы сработать переполнение....

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

smailik пишет:
в программировании вроде нет.
Точно?

smailik пишет:

почему вывод в serial не заканчивается на 32767 ?

С какого перепугу ему заканчиваться? число типа int не может быть больше, чем 32767. Никогда и ни при каких обстоятельствах. У Вас стоит условие <=32767  - это условие истинно всегда, значит цикл бесконечный. С какого бодуна ему заканчиваться?

Если Вас интересует почему при этом не начинаю печататься отрицательные числа, посмотрите какие есть перегруженные методы print в классе Print - всё поймёте.

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Если Вас интересует почему при этом не начинаю печататься отрицательные числа, посмотрите какие есть перегруженные методы print в классе Print - всё поймёте.

меня интересует, откуда у него начинают появляться числа "вплоть до 300 000"

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

приведенный вами код печатает строго от 32000 до 32767.

Да, ладно!

Вот мой код:

void setup(void) {
	Serial.begin(9600);
	for (int i=32765; i <= 32767; i++) {
		Serial.println(i);
		delay(1000);
	}
}	
void loop(void) {}

А вот его печать

32765
32766
32767
32768
32769
32770
32771
32772
32773
32774
32775
32776
32777
и т.д.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

меня интересует, откуда у него начинают появляться числа "вплоть до 300 000"

Оттуда же, откуда у меня в посте #5 появляются числа вплоть до 32777 (дальше я дожидаться не стал :-)

smailik
Offline
Зарегистрирован: 08.04.2021

Спасибо за быстрый отклик. Код редуцирован от исходного, в котором были функции для опроса EEPROM и записи дампа на SD карту.
И вот именно приведенный код загружался в китайский клон Arduino Nano.
Запускаем монитор порта и видим.
START
32000
32001
...
32767
32768
32769
...
65535
65536
65537
Дождался значений больше миллиона.

у меня нет объяснений. 
Сначала в цикле было одно условие i <= 32767. Потом я понял, что после достижения счетчиком значения 32767 и инкрементации счетчик станет равным -32768. Добавил второе условие i >= 0.
Однако после загрузки скетча в монитор порта выводятся бесконечно возрастающие положительные числа.  

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

b707 пишет:

приведенный вами код печатает строго от 32000 до 32767.

Да, ладно!

Вот мой код:

а вот мой :)

#include <stdio.h>
void main() {
int ii;
 for (ii =32000; ii >=0 && ii <= 32767; ii++) {

  printf("i = %d\n",ii);
 }
}

и он печатает строго от 32000 до 32767 :)

 

(ладно-ладно, ошибку уже понял)

Осталься только вопрос. откуда ТС получил числа больше 65565 ?

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Оттуда же, откуда у меня в посте #5 появляются числа вплоть до 32777 (дальше я дожидаться не стал :-)

ну на 0xFFFF разве не должно все закончится? - или я тоже чего-то не понимаю

mixail844
Offline
Зарегистрирован: 30.04.2012

b707 пишет:

Осталься только вопрос. откуда ТС получил числа больше 65565 ?

ЕвгенийП пишет:

 перегруженные методы print в классе Print - всё поймёте.

поэтому ? 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

smailik пишет:
у меня нет объяснений.

У меня есть. Я всё описал в посте №5. Вы читаете, что Вам пишут или только "писатель"?

smailik пишет:
Добавил второе условие i >= 0

В таких случаях надо выкладывать получившийся код, т.к. нам неоткуда знать, что и как Вы добавили. Но в данном случае всё так и должно происходить, как Вы написали. См. последнюю фразу всё в том же посте №5

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

ну на 0xFFFF разве не должно все закончится? - или я тоже чего-то не понимаю

Вы просто давно (или никогда) не смотрели код класса Print. Метод для печати int выглядит вот так:

size_t Print::print(int n, int base)
{
  return print((long) n, base);
}

Спасибо разработчикам класса Print. Конечно же, это голимый ляп.

smailik
Offline
Зарегистрирован: 08.04.2021

Согласен, int > 32767 никогда не будет. После инкрементации int равного 32767 значение должно стать -32 768
условие i >= 0 становится false - цикл завершается. По факту - фиг.
По поводу перегруженных методов print в классе Print. По факту счетчик int - два байта в ОЗУ, которые могут принять 65536 различных значения. Откуда в мониторе бесконечно возрастающие значения, больше 65536.

smailik
Offline
Зарегистрирован: 08.04.2021

В первом посте приведен код, который грузился в Arduino Nano и который мы обсуждаем.

Там описание цикла выглядит вот так 
 for (int i = 32000; i >= 0 && i <= 32767; i++)

b707
Offline
Зарегистрирован: 26.05.2017

smailik пишет:

В первом посте приведен код, который грузился в Arduino Nano и который мы обсуждаем.

Там описание цикла выглядит вот так 
 for (int i = 32000; i >= 0 && i <= 32767; i++)

еще раз - у меня этот цикл пробегает от  32000  до 32767 один раз и останавливается.

проверяю в Линуксе, ардуины на работе нет. Переменная i имеет тип int16_t

smailik
Offline
Зарегистрирован: 08.04.2021

Arduino под рукой нет? Залейте, пжлст, скетч из первого поста и проверьте. Я тоже понимаю, что так быть не должно, но ведь выходит :(

smailik
Offline
Зарегистрирован: 08.04.2021

Понятно. В нормальных C/C++ этот код так и должен работать.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Вот у меня тоже работает таким странным образом.

Если заменить int на unsigned int код работает, как ожидается.

Мне в голову приходит только одно объяснение:

1. Оптимизатор удаляет проверки.

2. Метод print каким-то образом из int делает long, и код выполняется так, как если было long.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

проверяю в Линуксе, ардуины на работе нет. Переменная i имеет тип int16_t

Да, в ардуине из коробки так, как он говорит. У тебя просто в опциях оптимизации другие.

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Вы просто давно (или никогда) не смотрели код класса Print. Метод для печати int выглядит вот так:

size_t Print::print(int n, int base)
{
  return print((long) n, base);
}

Спасибо разработчикам класса Print. Конечно же, это голимый ляп.

рискну показаться тупым, но по-моему это ничего не обьясняет. Если параметр n в заголовке функции описан как int -как он может передать в тело функции значение, большее чем 0xFFFF ???

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

smailik,

Вы задаёте много РАЗНЫХ вопросов оптом и не внимательно читаете ответы.

Давайте схаваем этого слона по частям.

1. Почему не заканчивается при условии i <= 32767 я Вам объяснил. Надеюсь. Вы поняли.

2. Условия типа i > 0 выбрасывает оптимизатор, т.к. он видит, что число и так больше 0 и только увеличивается (ну, вот такой он)

3. Печатается в методе Print::print ВСЕГДА long. Если Вы поставите более аккуратную печать, например

char buf[12];
sprintf(buf, "%d", i);
Serial.println(buf);

будут отрицательные числа и море счастья.

Все вопросы закрыты?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

Если параметр n в заголовке функции описан как int -как он может передать в тело функции значение, большее чем 0xFFFF ???

Посмотрите ассемблерный код.

smailik
Offline
Зарегистрирован: 08.04.2021

Да, перегруженная функция действительно выводит int как long (спасибо за объяснение ЕвгенийП).
Но это не объясняет того, как сам int может стать больше 0xFFFF.
И это странный оптимизатор, который из двух условий, объединенных логическим И - одно отбрасывает.

  

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Посмотрите ассемблерный код.

негде  :(

подозреваю. что это очередная "оптимизация" и все вызовы метода для печати инт еще на этапе компиляции подменяется на печать лонг. Это (для меня) обьяснило бы остальное. но как-то очень криво это все...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

smailik,

запомните. Возле переполнения всегда случаются странные вещи. Причём у разных компиляторов/оптимизаторов - разные. Если Вам нужно работать возле переполнения, то лучший выход - взять тип данных подлиннее. В данном случае отца русской демократии спасёт unsigned. Если надо работать возле переполнения unsigned - берите long. Трахаться с переполнением есть смысл только тогда, когда длиннее переменных уже нет.

Не ходите по ночам на болота.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

smailik пишет:

Да, перегруженная функция действительно выводит int как long (спасибо за объяснение ЕвгенийП).
Но это не объясняет того, как сам int может стать больше 0xFFFF.
И это странный оптимизатор, который из двух условий, объединенных логическим И - одно отбрасывает.

Вам тоже совет из поста #22

smailik
Offline
Зарегистрирован: 08.04.2021

Еще раз спасибо. Насчет оптимизатора - звучит правдоподобно. Хотя очень криво. А вдруг я со счетчиком что-то еще в цикле делаю, например уменьшаю. Теперь при составлении сложных условий надо еще соображать, какие из них оптимизатор решит скипнуть.

По поводу метода print. int - это два байта в ОЗУ, значения от 0 до 0хFFFF. Как бы он не выводил тип int  - на входе все равно эти два байта. Как может получаться больше 0xFFFF? Согласен с b707, это крайне странно.

Тем не менее, большое спасибо за активное участие ЕвгенийП и b707.
Мир не идеален :) Примем эти странности как особенность и будем осторожны на границе overflow.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

b707 пишет:

ЕвгенийП пишет:

Посмотрите ассемблерный код.

негде  :(

подозреваю. что это очередная "оптимизация" и все вызовы метода для печати инт еще на этапе компиляции подменяется на печать лонг. Это (для меня) обьяснило бы остальное. но как-то очень криво это все...

Так оно и есть:

1. Оптимизатор выбрасывает все сравнения, единственной операцией с i стается только i++.

2. Операцию i++ оптимизатор переносит внутрь print.

3. А внутри print переменная i уже имеет тип long, что мы и видим на печати.

Можно проанализировать листинги:

В варианте с int присутствует следующий фрагмент, который отсутствует в варианте с unsigned int

size_t Print::print(unsigned int n, int base)
{
  return print((unsigned long) n, base);
}

size_t Print::print(long n, int base)
 378:	cf 92       	push	r12
 37a:	df 92       	push	r13
 37c:	ef 92       	push	r14
 37e:	ff 92       	push	r15
 380:	cf 93       	push	r28
 382:	df 93       	push	r29
 384:	6b 01       	movw	r12, r22
 386:	7c 01       	movw	r14, r24
  return write(str);
}

size_t Print::print(char c)
{
  return write(c);
 388:	e0 91 25 01 	lds	r30, 0x0125	; 0x800125 <Serial>
 38c:	f0 91 26 01 	lds	r31, 0x0126	; 0x800126 <Serial+0x1>
 390:	01 90       	ld	r0, Z+
 392:	f0 81       	ld	r31, Z
 394:	e0 2d       	mov	r30, r0
 396:	6d e2       	ldi	r22, 0x2D	; 45
 398:	85 e2       	ldi	r24, 0x25	; 37
 39a:	91 e0       	ldi	r25, 0x01	; 1
 39c:	09 95       	icall
 39e:	ec 01       	movw	r28, r24
  if (base == 0) {
    return write(n);
  } else if (base == 10) {
    if (n < 0) {
      int t = print('-');
      n = -n;
 3a0:	66 27       	eor	r22, r22
 3a2:	77 27       	eor	r23, r23
 3a4:	cb 01       	movw	r24, r22
 3a6:	6c 19       	sub	r22, r12
 3a8:	7d 09       	sbc	r23, r13
 3aa:	8e 09       	sbc	r24, r14
 3ac:	9f 09       	sbc	r25, r15
      return printNumber(n, 10) + t;
 3ae:	4a e0       	ldi	r20, 0x0A	; 10
 3b0:	0e 94 7b 01 	call	0x2f6	; 0x2f6 <_ZN5Print11printNumberEmh.constprop.9>
    }
    return printNumber(n, 10);
  } else {
    return printNumber(n, base);
  }
}
 3b4:	8c 0f       	add	r24, r28
 3b6:	9d 1f       	adc	r25, r29
 3b8:	df 91       	pop	r29
 3ba:	cf 91       	pop	r28
 3bc:	ff 90       	pop	r15
 3be:	ef 90       	pop	r14
 3c0:	df 90       	pop	r13
 3c2:	cf 90       	pop	r12
 3c4:	08 95       	ret

000003c6 <__cxa_pure_virtual>:

а в варианте с unsigned int, наоборот, присутствует фрагмент, отсутствующий в варианте с int:

void fffff() {
  for (unsigned int i = 32000; i >= 0 && i <= 32767; i++)
 60a:	c1 14       	cp	r12, r1
 60c:	80 e8       	ldi	r24, 0x80	; 128
 60e:	d8 06       	cpc	r13, r24
 610:	e1 04       	cpc	r14, r1
 612:	f1 04       	cpc	r15, r1
 614:	d1 f6       	brne	.-76     	; 0x5ca <main+0x10a>
  return write(s.c_str(), s.length());
}

size_t Print::print(const char str[])
{
  return write(str);
 616:	8b e1       	ldi	r24, 0x1B	; 27
 618:	91 e0       	ldi	r25, 0x01	; 1
 61a:	0e 94 69 01 	call	0x2d2	; 0x2d2 <_ZN5Print5writeEPKc.constprop.13>
  return x.printTo(*this);
}

size_t Print::println(void)
{
  return write("\r\n");
 61e:	88 e1       	ldi	r24, 0x18	; 24
 620:	91 e0       	ldi	r25, 0x01	; 1
 622:	0e 94 69 01 	call	0x2d2	; 0x2d2 <_ZN5Print5writeEPKc.constprop.13>
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
 626:	0e 94 5f 01 	call	0x2be	; 0x2be <_Z14serialEventRunv>
 62a:	fd cf       	rjmp	.-6      	; 0x626 <main+0x166>

 

smailik
Offline
Зарегистрирован: 08.04.2021

Насчет изучения ассемблерного кода.
Я использую Arduino для быстрого решения мелких прикладных задач. И ожидаю от несложного кода на несложном языке предсказуемого поведения. Тратить время на изучение конкретной имплементации методов просто нет.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ЕвгенийП пишет:

smailik,

запомните. Возле переполнения всегда случаются странные вещи. Причём у разных компиляторов/оптимизаторов - разные. Если Вам нужно работать возле переполнения, то лучший выход - взять тип данных подлиннее. В данном случае отца русской демократии спасёт unsigned. Если надо работать возле переполнения unsigned - берите long. Трахаться с переполнением есть смысл только тогда, когда длиннее переменных уже нет.

Не ходите по ночам на болота.

Ну да, достаточно вспомнить тему про "святое переполнение миллис". И утверждение, что при правильной обработке переполнения никаких проблем никогда не бывает.

А теперь обращаем внимание на выделенные слова и думаем, которому из ЕвгениевП верить: который в теме про миллис, или который в теме про int в цикле for.

4ЕвгенийП: ничего личного.

smailik
Offline
Зарегистрирован: 08.04.2021

andriano, спасибо Вам за такой подробный обзор.  Теперь вопрос точно закрыт.
Но работа оптимизатора повергает в шок. Особенно вот это

2. Операцию i++ оптимизатор переносит внутрь print. 

Топик можно закрывать.
Всем спасибо.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

smailik пишет:

Насчет изучения ассемблерного кода.
Я использую Arduino для быстрого решения мелких прикладных задач. И ожидаю от несложного кода на несложном языке предсказуемого поведения. Тратить время на изучение конкретной имплементации методов просто нет.

Ну тогда пишите сразу правильно. И никогда не пишите int i ... i <= 32767, и будет Вам счастье.

Другими словами, глюки компилятора проявляются исключительно на неправильном коде.

 

И еще, сюда же. Если Вы хотите писать несложный код с предсказуемым поведением, то, боюсь, Вы выбрали не самый подходящий язык. Паскаль бы с этим справился гораздо лучше. А Си предполагает, что программист знает, что делает, и отчетливо осознает, почему делает именно так.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

andriano пишет:

 Паскаль бы с этим справился гораздо лучше. А Си предполагает, что программист знает, что делает, и отчетливо осознает, почему делает именно так.

Ой! В 1984-ом году я учился в матшколе и было мне 15 лет. Вместо быдляцкого УПК, у нас было программирование, которое вели ребята из ИПМ. Так вот я сломал БЭСМ-6 у них в ВЦ программой НА ПАСКАЛЕ ;))))))). Причем я её на синем бланке отдавал в перфорацию, то есть её много раз проверяли ;)). Но то, что я во вложенных циклах файлы открываю, никто не заметил... Защиты от большого числа открытых файлов в системе не было :(.

Я - не нарочно, не ожидал таких последствий ;)). Хотел сделать просто мелкую пакость. ИПМ-шики, как ни странно не обиделись, а зауважали. Хорошие были времена!

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

wdrakula пишет:

Ой! В 1984-ом году...

Влад, я думаю, что ты завалил не компилятор, а ОС. Так что Паскаль здесь ни при чем. Он не обязан знать ограничения ОС.

smailik
Offline
Зарегистрирован: 08.04.2021

Цитата:

И еще, сюда же. Если Вы хотите писать несложный код с предсказуемым поведением, то, боюсь, Вы выбрали не самый подходящий язык. Паскаль бы с этим справился гораздо лучше. А Си предполагает, что программист знает, что делает, и отчетливо осознает, почему делает именно так.

Andriano, под несложным кодом я подразумевал легко читаемый код, в основном состоящий из функций, простых классов, циклов, операторов условного ветвления т.е. процедурное программирование + немножко ООП. Без лямбда-функций, перегрузок и прочих премудростей.

Я в первую очередь использую Arduino для быстрого решения несложных задач по автоматизации, а в Arduino IDE Си по дефолту и речь о выборе языка программирования не особо стоит.

А на Паскале последний раз кодил в 90-х, создавали ПО для различных количественных и качественных оценок гистологических срезов (медицина). Легкий оффтоп.  

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:

всегда случаются странные вещи.

проблем никогда не бывает.

которому из ЕвгениевП верить

Обоим. "странные вещи" != "проблемы".

b707
Offline
Зарегистрирован: 26.05.2017

smailik пишет:

Я в первую очередь использую Arduino для быстрого решения несложных задач по автоматизации, а в Arduino IDE Си по дефолту и речь о выборе языка программирования не особо стоит.

это все хорошо, только упаси вас бог скатываться в ересь "у меня слишком мало времени чтобы углубляться в нюансы".

Обычно так говорят убогие лентяи, которые реально и не думали никуда углублятся. Этот путь не приведет ни к чему хорошему - как в программировании, так и особенно - в общении тут на форуме :)

smailik
Offline
Зарегистрирован: 08.04.2021

b707 пишет:

это все хорошо, только упаси вас бог скатываться в ересь "у меня слишком мало времени чтобы углубляться в нюансы".

Обычно так говорят убогие лентяи, которые реально и не думали никуда углублятся. Этот путь не приведет ни к чему хорошему - как в программировании, так и особенно - в общении тут на форуме :)

Та ни в жисть :) Просто рациональное использование самого драгоценного ресурса.
За совет спасибо, особенно насчет форума. Уже получил определенное представление :)

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ЕвгенийП пишет:

andriano пишет:

всегда случаются странные вещи.

проблем никогда не бывает.

которому из ЕвгениевП верить

Обоим. "странные вещи" != "проблемы".

Приношу свои извинения: отсутствие проблем, действительно, выглядит очень странным, если не сказать подозрительным.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

smailik пишет:

Я в первую очередь использую Arduino для быстрого решения несложных задач по автоматизации, а в Arduino IDE Си по дефолту и речь о выборе языка программирования не особо стоит.

Нет, ну вопрос о том, почему авторы Ардуино в качестве основного языка выбрали Си/Си++, думаю, выходит за рамки настоящей темы. Я просто хотел сказать, что, коль Вы выбрали систему (Ардуино), в которой используются Си/Си++, то "Тратить время на изучение" придется, хотите Вы этого или нет.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

smailik пишет:

Без лямбда-функций, перегрузок и прочих премудростей.

Ну это ж колебание основ и противу всяких скреп! Щаз Пуха натравим на еретика! ;)))

Как ж без лямбд? Решительно не понимаю!

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

andriano пишет:

Влад, я думаю, что ты завалил не компилятор, а ОС. Так что Паскаль здесь ни при чем. Он не обязан знать ограничения ОС.

Тут и думать не нужно. Как можно компилятор, "завалить"? Ты ж сказал, что на Паскале новичок не сделает много ошибок (ну я так тебя понял) - я показал, как именно можно сделать большие ошибки. Фсё. ;))

Это просто трёп, Сереж! Не диспут.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

wdrakula пишет:

Ты ж сказал, что на Паскале новичок не сделает много ошибок (ну я так тебя понял)

Нет, я имел в виду, что компилятор Паскаля сообщит новичку о гораздо большем проценте имеющихся ошибок, тогда как компилятор Си будет считать написанное не за ошибку, а что программист именно "хотел чего-то странного". Поэтому написанная новичком программа, которую пропустит компилятор, на Си будет иметь гораздо большую вероятность "работать как-то странно", чем на Паскале.

Короче: Си не прощает ошибок, хотя внешне выглядит все наоборот.

smailik
Offline
Зарегистрирован: 08.04.2021

Попробую резюмировать весь топик.

Причины "странного" исполнения кода были выявлены в кратчайшие сроки. 
Их оказалось три:

1. "Неправильное" написание мною кода.
2. Как следствие пункта 1 - кривая работа оптимизатора, выкинувшего все условия проверки значения счетчика.
3. Кривая реализация метода Print для int.

Насчет пункта 1 - попробую слабенько защититься. Код, конечно, "скользкий". Но вот у b707 под Линуксом этот же код скомпилился нормально и отработал ожидаемо. Ладно, согласен, отмаза так себе.

В процессе обсуждения получил массу советов.
1. Учиться.
2. Не лениться.
3. Выбрать для себя ЯП попроще, соответственно уровня. Но так как для Arduino альтернативы Си практически нет - то
   3.1 - Попросить у Гудвина мозгов
   3.2 - см. п. 1 и 2.
4. Быть внимательным и готовым к неожиданному поведению кода при работе рядом с границами предельно допустимых значений типа.
Стараться избегать таких ситуаций, используя более длинные типы. 

Узнал, что Си - это для реальных пацанов, он, как мамка, за тобой следить не будет.
Максимально толерантен к странному стилю программирования.

- Хотите, чтобы я откомпилировал этот код? ОКей, счас сделаем, но потом, как сказал Сусанин полякам - "Дальше сами!".
Ну и чтобы совсем не скучно было, я его еще пооптимизирую немного :)

Что имеем в сухом остатке.
Причины проблемы выявлены, предложены пути ее решения, за что я искренне благодарен всем участникам обсуждения.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andriano пишет:
Паскаля
Ну,конечно Паскаль стал героем классической статьи о предпочтения настоящих программистов, но так уж совсем ставить на нём крест не надо. Там тоже есть такой полезный тип данных, как указатель :-)

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

smailik пишет:

Что имеем в сухом остатке.

Причины проблемы выявлены, предложены пути ее решения, за что я искренне благодарен всем участникам обсуждения.

Ты просто warning-и включи и читай, как тебя за глаза материт компилятор

smailik
Offline
Зарегистрирован: 08.04.2021

DetSimen пишет:

Ты просто warning-и включи и читай, как тебя за глаза материт компилятор

Включил варнинги (-Wall -Wextra) - при компиляции тишина. (Или не так включил?)
Отключил оптимизацию всю (Os -> O0) - скетч отработал, как положено, но размер скомпилированного кода вырос в 5 раз :( Нафик-нафик. Вернул оптимизацию взад.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

smailik пишет:
Включил варнинги (-Wall -Wextra) - при компиляции тишина.
Скетч в студию.
smailik пишет:
Или не так включил?
Может и не так, Вы же не написали как включили.

Содержимое platfroms.txt и скриншот окна "Настройки" Arduino IDE  в студию.

smailik
Offline
Зарегистрирован: 08.04.2021

ЕвгенийП пишет:

Содержимое platfroms.txt и скриншот окна "Настройки" Arduino IDE  в студию.

Скетч все тот же самый.

В настройках

Показать подробный вывод - Компиляция - стоит галка
Сообщения компилятора - Все

Вот начало platform.txt, остальная часть без изменений


# Arduino AVR Core and platform.
# ------------------------------
#
# For more info:
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification

name=Arduino AVR Boards
version=1.8.3

# AVR compile variables
# ---------------------

#compiler.warning_flags=-w
compiler.warning_flags=-Wall -Wextra
compiler.warning_flags.none=-w
compiler.warning_flags.default=
compiler.warning_flags.more=-Wall
compiler.warning_flags.all=-Wall -Wextra

# Default "compiler.path" is correct, change only if you want to override the initial value
compiler.path={runtime.tools.avr-gcc.path}/bin/
compiler.c.cmd=avr-gcc
compiler.c.flags=-c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects
#compiler.c.flags=-c -g -O0 {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects
compiler.c.elf.flags={compiler.warning_flags} -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections
#compiler.c.elf.flags={compiler.warning_flags} -O0 -g -flto -fuse-linker-plugin -Wl,--gc-sections
compiler.c.elf.cmd=avr-gcc
compiler.S.flags=-c -g -x assembler-with-cpp -flto -MMD
compiler.cpp.cmd=avr-g++
compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto
#compiler.cpp.flags=-c -g -O0 {compiler.warning_flags} -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto
compiler.ar.cmd=avr-gcc-ar
compiler.ar.flags=rcs
compiler.objcopy.cmd=avr-objcopy
compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0
compiler.elf2hex.flags=-O ihex -R .eeprom
compiler.elf2hex.cmd=avr-objcopy
compiler.ldflags=
compiler.libraries.ldflags=
compiler.size.cmd=avr-size

 

 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

smailik, вот я реально хочу запустить, посмотреть что там и, если получится, чем-то Вам помочь. Ну, не пишите Вы мне

smailik пишет:
Скетч все тот же самый.
не заставляйте меня рыться по теме и думать какой из десятка скетчей тут "тот же самый". Вам что, трудно его выложить?

Вообще, создавать дополнительные трудности тому, кто хочет Вам помочь - так себе идея.