Почему большинство функций Arduino возвращают -1 вместо 0

Многие функции Arduino возвращают -1, если что-то «не получается». Например, Serial.read возвращает -1 или печально известную ÿ, когда эта функция вызывается, когда последовательный буфер пуст.

Как встроенный программист C, я лично сторонник того, чтобы функции возвращали данные в форме изменения указателей, которые указывают на переданные адреса и возвращаемые состояния с фактической функциональностью возврата функции. Я привык возвращать 0, если функция «не выполнена» или «сбой».

Я не вижу логики в том, почему многие функции Arduino возвращают тип int, содержащий -1, а не просто 0.

Не лучше ли позволить функциям возвращать логический тип или беззнаковый тип char, в котором false или '0' будут указывать на "сбой" процесса, а true или '1' - на "успешный" процесс?

Также: если я наберу: if(Serial.read()) {/* body */ а Serial.read() возвращает -1, поскольку буфер пуст. Будет ли выполнено тело If или нет?

, 👍2

Обсуждение

как бы вы вернули байт со значением 0 из read(), если 0 указывает на ошибку?, @Juraj

Их, вероятно, можно обсудить в зависимости от функции. Сериал, например. Вы должны подтвердить, что Serial. available() > 0 перед попыткой Serial.read(). Если я ожидаю, что 8 байтов придут с конечным символом, я проверяю Serial. available()> 8, прежде чем запускать цикл Serial.read(), чтобы перенести данные в массив или аналогичный, а затем проверить байт является правильным конечным символом., @CrossRoads

@Juraj Я понял, что `Serial.read()`, возможно, был очень плохим примером, поскольку эта функция возвращает оба возвращаемых значения в виде состояния (-1). Возможно, `Serial.begin()` будет лучшим примером, @bas knippels


4 ответа


0

Я подозреваю, что это наследие командного программирования Unix, которое сначала было реализовано на C. Для команд, которые должны были возвращать только состояние, а не данные, возвращаемое значение, равное нулю, означало успех, а любое другое возвращаемое значение указывало на какую-то ошибку. . При желании отдельные программисты могут назначать определенные ненулевые значения для определенных типов ошибок.

Помните, что возвращаемое значение возвращается вызывающей функции в регистр. И в наши дни термин "Arduino" охватывает широкий спектр архитектур, включая 32-разрядную ARM Cortex-M. Указание, что возвращаемое значение является символом, в этом случае не дает никаких преимуществ.

Тип данных boolean — сравнительно недавнее дополнение к языку C, поэтому неудивительно, что вы не видите его частого использования в существующих переносимых библиотеках.

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

Если вам действительно нужен контроль над типами данных, включите stdint.h и используйте определенные в нем типы. Если вам нужно 8-битное значение без знака, используйте uint8_t, а не unsigned char. Если вы хотите, чтобы компилятор выбрал наилучший тип данных длиной не менее 8 бит, используйте uint_fast8_tf.

,

3

Точно ничего утверждать не могу, так как не участвовал в разработке API Ардуино. Однако, как и Эллиот Олдерсон, я подозреваю, что был вдохновлен традиционными C API. Страница руководства для getchar(), которая является очень старой функцией из стандартной библиотеки C, гласит:

fgetc(), getc() и getchar() возвращают прочитанный символ как unsigned char, преобразованный в int или EOF в конце файла или ошибка.

Учитывая, что EOF обычно определяется как -1, это согласуется с поведение Serial.read().

Удобство для новичков также является основной целью API. Указатели известно, что это огромная трудность для начинающих.

Кроме того, могут быть задействованы некоторые соображения эффективности. Ардуино стартовал на платформе AVR. Это RISC-архитектура с большим количество общих регистров ЦП (а именно 32). Обычно компилятор удается разместить большинство локальных переменных в регистрах. Вызов соглашение гарантирует, что в большинстве случаев параметры функции и возврат значения также проходят через регистры процессора. Это означает, что мы можем избежать большого количества оперативной памяти. доступ, который по своей природе намного медленнее, чем доступ к регистру. Используя Соглашение о возврате по указателю нарушает эту оптимизацию.

Наконец, хорошо, что простые вещи легко писать. Для например, интерпретатор для односимвольных команд может быть очень легко пишется как:

switch (Serial.read()) {
case 'a':
    do_command_a();
    break;
case 'b':
    do_command_b();
    break;
// и т. д...
}

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

,

0

-1 возвращается, когда "0" является абсолютно допустимым ответом.

В качестве примера для Serial.read(): 0 — допустимый байт или символ ASCII. -1 нет. Если бы вы вернули 0 для "неудачи", тогда не было бы способа отличить это от действительного значения байта 0.

,

Вы уверены, что Serial.read() не может возвращать двоичные значения, а не только ASCII? Я не могу найти это в документации., @Elliot Alderson

Что такое ASCII? Это просто формы, которые люди решили ассоциировать с числами. Все есть числа. Числа от 0 до 255 — и мы решили, что некоторые из этих чисел будут представлять буквы в нашем сознании. Serial.read() возвращает следующий байт в приемном буфере. Этот байт равен 0-255, и если мы хотим, чтобы 65 означало «А», мы можем это сделать. Но если нет байта для возврата из приемного буфера, то должно быть возвращено что-то «не байт», означающее «там чепуха, брув!», а -1 не является байтом., @Majenko

Итак, недостающий бит информации заключается в том, что мы предполагаем, что int определено как большее, чем 8 бит, а Serial.read() возвращает int, а не char. Значение char, равное 0xFF, может быть допустимым возвращаемым значением, но значение int, равное 0xFFFF, таковым не является., @Elliot Alderson

Это не предположение. Это холодный суровый факт. Int всегда будет больше байта., @Majenko

Согласен, учитывая компилятор ANSI. Я не должен был говорить «предполагая», я должен был сказать «признавая»., @Elliot Alderson


1

Arduino API — это порт обработки. Обработка — это Java API для связи с MCU, работающим под управлением Firmata. Arduino позволяет запускать скетчи с одним и тем же API непосредственно на микроконтроллере.

Так, например, потоковые функции из потоковых классов Java были перенесены в API Arduino. Сюда входит функция read() для чтения один байт. Конечно, Java и базовые библиотеки Java вдохновлены C++.

Для других функций чтения и записи, если возвращаемое значение представляет собой количество записанных или прочитанных байтов, то 0 является допустимым возвращаемым значением, а -1 указывает на ошибку.

Processing, Wiring и Arduino были созданы преподавателями и студентами интерактивных искусств, а не разработчиками встроенных систем. Так что можно не удивляться используемым не идеальным типам данных. Позже некоторые вещи были улучшены разработчиками программного обеспечения.


как разработчик встроенного C, вы должны знать, что:

  • 0 – допустимое значение для чтения, поэтому оно не может быть значением, указывающим на ошибку
  • 'if' выполняется, если оцениваемое значение не равно 0
,

Как это отвечает на вопрос? Вы ничего не сказали о возвращаемых значениях., @Elliot Alderson

извините, вы не знакомы с функцией чтения Java. Я добавил ссылку на JavaDoc функции чтения () Java. и я обратился к мысленной ошибке OP о возвращаемом значении ошибки read() в комментарии, @Juraj

На форуме Arduino, я думаю, вы должны предположить, что читатели не знакомы с Java. Кроме того, не могли бы вы включить важную информацию прямо в свой ответ на случай, если ссылка когда-нибудь сломается?, @Elliot Alderson

Итак, чтобы добраться до сути вопроса, можете ли вы объяснить, почему (если на самом деле это правда) функции Java возвращают -1 вместо 1 (или True) для условия ошибки? Я имею в виду даже те функции, которые возвращают не значение байта, а только индикацию прохождения/непрохождения., @Elliot Alderson

@ElliotAlderson, это объясняется в вашем ответе :-). Я "вдохновлен C++", который вдохновлен C..., @Juraj

если возвращаемое значение представляет собой количество записанных или прочитанных байтов, то 0 является допустимым возвращаемым значением., @Juraj

Я не был уверен, будет ли `if(что-то)` также истинным, если что-то было подписанным И отрицательным. Я почти не использую типы значений со знаком., @bas knippels

Кроме того, как «разработчик встраиваемых систем на C», я знаю, что `Serial.read()` не нужно интерпретировать как символ. Насколько вы знаете, я использую `Serial.read()` для чтения массива чисел, который также может содержать 255, @bas knippels