в этом простом скетче указатель стека не меняется?

Я экспериментирую с переключением контекста, и моя первая идея — поиграть с SP и посмотреть, как он изменится. Однако Sp не делает то, что я ожидаю. Скетч ниже. Я использую Uno R3. Я ожидаю увидеть, что SP сначала должен распечатать какое-то значение, а затем оно должно быть на 4 целых числа дальше (4x2 байта?) при печати во второй раз. Но этого не происходит, и оба раза я вижу одно и то же значение SP. В чем может быть проблема?

    void setup() {
  // put your setup code here, to run once:

  Serial.begin(9600);

  Serial.print("X = ");
  Serial.println(SP,HEX);
}
void loop() {
  // put your main code here, to run repeatedly:
Serial.print("BEFORE: ");
Serial.println(SP,HEX);
int y = 15;
int z = y;
int g = z + y;
int dsf = z-y;
  Serial.println(dsf+g); //this should make these variables DO something...
  Serial.print(" After = ");
  Serial.println(SP,HEX);
  delay(1000);
}

, 👍0

Обсуждение

Почему вы предполагаете, что стек изменится? Ядро AVR имеет 32 регистра. Много места для хранения небольших временных переменных, подобных этим. Добавьте к этому тот факт, что компилятор оптимизирует множество вещей, которые ему не нужны, и вы получите почти ничего., @Majenko

Верный пункт. Однако в аналогичном скетче, который на самом деле вызывал функцию, единственной ролью которой была распечатка SP, SP по-прежнему не менялся. Если я понимаю вызовы функций (а возможно, и нет), то, по крайней мере, адрес возврата должен находиться в стеке в этот момент, не так ли?, @Michael Stachowsky

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

Вам также следует прочитать это: https://gcc.gnu.org/wiki/avr-gcc - особенно разделы соглашения о вызовах и макета кадра., @Majenko

Спасибо, сделаю. Если вы суммируете комментарии в качестве ответа, я приму, @Michael Stachowsky

Вы можете использовать setjmp/longjmp для переключения контекста. В качестве примера см. https://github.com/mikaelpatel/Arduino-Scheduler/blob/master/src/Scheduler.cpp#L124., @Mikael Patel

@MikaelPatel: я установил/перепрыгнул кучу в предыдущем коде. Однако я хочу сделать это самостоятельно, чтобы посмотреть, как это делается. В противном случае я бы просто скачал FreeRTOS или что-то в этом роде., @Michael Stachowsky

@MichaelStachowsky Вот это дух! Вот ссылка, которая может дать некоторое представление. https://github.com/vancegroup-mirrors/avr-libc/blob/master/avr-libc/libc/stdlib/setjmp.S Написание этого на C/C++ создаст дополнительную проблему :), @Mikael Patel


2 ответа


Лучший ответ:

2

Невозможно таким образом угадать компилятор. Вам нужно понять несколько вещей:

  • Компилятор оптимизирует любые переменные, которые просто присваиваются другим переменным в ходе вычислений и больше не используются.
  • ЦП AVR имеет 32 регистра. Более чем достаточно, чтобы не нуждаться использовать ОЗУ для хранения значений для такого простого скетча.

Сделать переменные изменчивыми, безусловно, поможет, поскольку это заставляет компилятор помещать их в память. Однако вам действительно следует изучить ассемблерный код, который создает компилятор, чтобы точно знать, что он делает.

,

3

Другой способ оптимизации компилятора — встроенная компиляция небольших или одноразовых функций. То, что вы ожидали, будет заключено в последовательность вызова и возврата, может и не быть.

Вставка __attribute__ ((noinline)) перед определением функции может подавить эту оптимизацию:

__attribute__ ((noinline)) void foo(int bar)
{
   // do something
}

подавляет встраивание в функцию foo(). Встраивание не раз мешало моим исследованиям, поэтому я создал этот более простой для запоминания макрос. (Ключевое слово — это просто __NOINLINE; предложение #else используется для того, чтобы «кто-то» случайно не попытался использовать декларатор «__attribute...» с другим компилятором, который этого не делает. не узнаю).

// Don't compile this function inline
//   '__NOINLINE void foo(void){ ... }'
#ifdef __GNUC__
#define __NOINLINE  __attribute__ ((noinline))
#else
#define NOINLINE error 'NOINLINE' not defined for this compiler
#endif
,

Даже небольшие многофункциональные функции могут быть встроены., @Nick Gammon

Я заметил, что gcc более склонен к встраиванию, поскольку Arduino IDE начала предоставлять ему опцию компилятора -flto. До этого момента он не встраивал никакие нетривиальные нестатические функции., @Edgar Bonet