Что произойдет, если возникнет ошибка во время выполнения?

17

Что произойдет, если в программе будет ошибка во время выполнения? Будет ли остановлено выполнение программы? Есть ли какой-нибудь способ заставить Arduino сказать мне, в чем ошибка?

Парень в шляпе
источник

Ответы:

21

Сначала давайте рассмотрим несколько примеров того, что может пойти не так.

Неинициализированные локальные переменные

void setup() {
  int status;
  pinMode(13, OUTPUT);
  digitalWrite(13, status);
} 

Как отметил Эдгар Бонет в комментариях, локальные переменные, как statusв коде выше, неявно инициализируются компилятором C ++. Таким образом, результат кода выше является неопределенным. Чтобы избежать этого, убедитесь, что вы всегда присваиваете значения локальным переменным.

С глобальными и статическими переменными все немного по-другому:

Глобальные и статические переменные гарантированно будут установлены в 0 по стандарту C.

Источник: Справочное руководство AVR Libc - Часто задаваемые вопросы - Разве я не должен инициализировать все мои переменные?

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

Переполнение памяти

int array[10];
int v = array[100];
array[-100] = 10;

Первая проблема здесь в том, что вы не знаете, что будет назначено v, но хуже всего то, что вы не знаете, что вы испортили с назначением на позицию -100 of array.

Перейти к незаконной инструкции

void doSomething( void ) { 
    for (int i = 0; i < 1000; i++); 
}

void setup () 
{
    void (*funcPtr)( void );

    funcPtr = &doSomething;
    funcPtr(); // calls doSomething();

    funcPtr = NULL;
    funcPtr(); // undefined behavior
}

Первый вызов на funcPtr()самом деле будет вызовом doSomething(). Вызовы, подобные второму, могут привести к неопределенному поведению.

Другие плохие вещи, которые могут случиться

Ну, вы можете исчерпать ОЗУ, например. Что еще. В любом случае, я думаю, что ваша программа будет работать, вероятно, не так, как вы хотели.

Виды защиты

В компьютерных системах подобные проблемы обычно решаются на разных уровнях:

  1. Компилятором
  2. По времени выполнения языка программирования (как, например, в Java).
  3. Операционная система или процессор (если ваша память имеет доступ к позиции за пределами адресного пространства, зарезервированного для вашей программы, ОС или процессор могут иметь механизмы безопасности для предотвращения этого)

Arduinos имеют только ограниченную защиту компилятора и, вероятно, ничего другого. Хорошей новостью является то, что они не являются многозадачными, поэтому затрагивается только ваша программа. В любом случае любая из этих ошибок приведет к ошибочному поведению.

Ответы

Предположения - это все проблемы, которые я изложил выше, это проблемы времени выполнения.

Что произойдет, если в программе будет ошибка во время выполнения?

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

Будет ли остановлено выполнение программы?

Нет, все будет продолжаться, как будто ничего необычного не произошло, вероятно, делая то, что вы не собирались делать. Это может сбросить или действовать беспорядочно. Он может превратить некоторые входы в выходы и сжечь один или два датчика (но это маловероятно ).

Есть ли какой-нибудь способ заставить Arduino сказать мне, в чем ошибка?

Я так не думаю. Как я уже говорил, механизмов защиты нет. Нет поддержки времени выполнения от языка, нет ОС, нет аппаратных проверок для доступа к памяти за пределами допустимого диапазона (загрузчик также не считается). Вы просто должны быть осторожны с вашей программой и, возможно, установить свои собственные сети безопасности.

Причина отсутствия защиты, вероятно, заключается в том, что контроллеры Arduino слишком дешевы, имеют слишком мало памяти и не должны запускать что-либо слишком важное (да, кажется, что где-то в AVR есть заявление об отказе от использования MCU, обычно используемых Arduino в системах жизнеобеспечения).

Рикардо
источник
1
Большой! Лучший ответ, который я видел на Arduino.SE до сих пор!
Парень со шляпой
1
Благодарность!! Я думаю, что мы должны стремиться дать как можно больше хороших ответов. Но меня немного беспокоит тот факт, что у нас не так много РЕАЛЬНЫХ ЭКСПЕРТОВ, которые могли бы посмотреть на ответы, подобные моим, и найти какие-либо явные ошибки. На самом деле, именно поэтому я разместил ответ, хотя я не так много знаю о микроконтроллерах AVR. Это посмотреть, если мы найдем кого-то, чтобы исправить это. Мы, конечно же, не хотим, чтобы такие умные штучки, как я, говорили что-то неправильное и не сходили с этого Но это, вероятно, обсуждение для сайта Meta.
Рикардо
5
@Ricardo - Я хотел бы сделать один комментарий, что неявно инициализированные переменные не обязательно неинициализированы. Переменные, определенные вне функций, обычно имеют так называемую «продолжительность автоматического хранения», которая затем инициализируется по умолчанию равной нулю. Для получения дополнительной информации см. En.cppreference.com/w/cpp/language/default_initialization . Поведение инициализации является достаточно сложным, поэтому на него, вероятно, опасно полагаться, но делать общие утверждения, вероятно, не очень хорошая идея.
Коннор Вольф
1
Кроме того, SRAM инициализируется на 0 при перезагрузке или запуске, так что вы можете сделать некоторые обоснованные предположения о неинициализированных переменных, если вы хотите жить опасно. Вы не должны полагаться на это поведение, но это интересно.
Коннор Вольф
1
Вот интересный пример того, что происходит, когда у вас заканчивается SRAM: electronics.stackexchange.com/questions/42049/… . По сути, стек забивает часть кучи, или наоборот. Это может делать интересные вещи, такие как повреждение части стекового фрейма (прерывание возврата функции и т. Д.) Или запись неверных данных в переменные.
Коннор Вольф
9

Нет никаких исключений времени выполнения. Есть только неопределенное поведение.

На самом деле, нет никаких исключений вообще . Если вы попытаетесь выполнить недопустимую операцию, ее результаты будут неизвестны.

Нет проверки времени выполнения вообще, кроме того, что вы реализуете. Ваша программа работает на железном железе. Это настольный эквивалент работы в ring-0 все время, потому что ATmega не имеет колец .

Коннор Вольф
источник
6

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

Затем вы должны повторно сбросить таймер в цикле. Если ваш код зависает в каком-то цикле условий, который никогда не закончится, то сторожевой таймер будет считать до нуля и в конечном итоге сбросить MCU.

Таким образом, вы теряете данные, но если вы запускаете AVR WDT в режиме прерывания, вы можете сохранить некоторые данные до сброса MCU.

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

Документация: AVR132: использование расширенного сторожевого таймера

институт океанографии
источник
5

Вам понадобится аппаратный отладчик для чего-то вроде этого. Но обычно вы увидите, что программа ведет себя не так, как вы ожидаете, и вам придется взглянуть на этот раздел кода, чтобы определить проблему.

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

Я считаю, что VisualMicro имеет некоторые встроенные функции отладки.

sachleen
источник
3

Я бы предположил, что процессор AVR не имеет каких-либо инструментов обнаружения ошибок или восстановления. Он может просто остановиться или продолжать игнорировать ошибку и последствия. Как сказал sachleen, вы должны добавить в вашу программу некоторые отладочные операторы, которые выводят данные в середине операции, чтобы проверить, работает ли она. Если вы используете emulaor и устанавливаете точки останова, вы можете легко найти проблему.

Доктор
источник
-2

Arduino перезагрузится (т.е. перезапустится setup()и loop()).

user28739
источник
1
Не обязательно. Ошибка во время выполнения может заставить программу зацикливаться без перезагрузки.
Ник Гэммон