Проблема с функцией, имеющей параметр со значением по умолчанию

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

Этот код дает "'blink' не был объявлен в этой области":

void loop(void) {
  blink(12, 2, 1000);
}

void blink(const uint8_t led, int num, const uint16_t l = 12) {
  Serial.println(led);
  Serial.println(num);
  Serial.println(l);
}

но это работает, если я не назначаю значение по умолчанию аргументу "l":

void blink(const uint8_t led, int num, const uint16_t l) {

или если я поставлю функцию blink перед циклом:

void blink(const uint8_t led, int num, const uint16_t l = 12) {
  Serial.println(led);
  Serial.println(num);
  Serial.println(l);
}

void loop(void) {
  blink(12, 2, 1000);
} 

, 👍2

Обсуждение

только объявление функции может иметь значение параметра по умолчанию. не то определение. таким образом, вы должны добавить прямое объявление, если хотите установить значения параметров по умолчанию., @Juraj

Путаница в коде mangler, который находится между вашим IDE-кодом и кодом GCC, который он генерирует, - это верный способ получить странные ошибки., @Peter Willard


2 ответа


0

Если вы используете функцию после ее вызова в том же файле, вы должны (или, по крайней мере, лучше) добавить так называемое "прямое объявление" перед ее вызовом. Лучшее место - перед первой функцией, и в вашем случае она должна выглядеть так:

void blink(const uint8_t led, int num, const uint16_t l);

Вы можете опустить = 12 или нет.

,

Обычно это делается Arduino IDE, и когда я не ставлю значение по умолчанию, "blink" можно определить после функции "loop", без "прямого объявления" перед ее вызовом. Я не понимаю, почему эта проблема существует только с параметром по умолчанию., @MichelBen

Причину этого, вероятно, лучше спросить в StackOverflow., @Michel Keijzers


10

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

Просто напомним: в C++ объявление функции должно быть замечено, чтобы сгенерировать ее вызов. Определение будет служить декларацией. В любом случае, один из них должен был быть замечен до места вызова. Генерация объявлений там, где это необходимо, - это, возможно, большая часть того, что делает процесс сборки Arduino, который, можно сказать, делает "язык" Arduino отличным от обычного C++.

Следующее было сгенерировано при работе с /tmp/default-param с "input", являющимся default-param.ino, запущенным:

arduino-cli -b arduino:avr:uno build --build-path /tmp/build

и инспектирование /tmp/build/sketch/default-param.ino.cpp который я называю "выводом". Вы можете использовать тот же процесс, если хотите точно увидеть, что процесс сборки делает с вашим кодом.

Аргумент Не по умолчанию

Этот вход:

void setup() {
    func(11);
}
void loop() {}
void func(int xyzzy) {}

генерирует:

#include <Arduino.h>
#line 1 "/tmp/default-param/default-param.ino"
#line 1 "/tmp/default-param/default-param.ino"
void setup();
#line 4 "/tmp/default-param/default-param.ino"
void loop();
#line 5 "/tmp/default-param/default-param.ino"
void func(int xyzzy);
#line 1 "/tmp/default-param/default-param.ino"
void setup() {
    func(11);
}
void loop() {}
void func(int xyzzy) {}

Процесс сборки вставил допустимое объявление функции C++ перед сайтом вызова, так что компилятор доволен.

С аргументом по умолчанию

Но этот ввод:

void setup() {
    func(11);
}
void loop() {}
void func(int xyzzy = 7) {}

генерирует:

#include <Arduino.h>
#line 1 "/tmp/default-param/default-param.ino"
#line 1 "/tmp/default-param/default-param.ino"
void setup();
#line 4 "/tmp/default-param/default-param.ino"
void loop();
#line 1 "/tmp/default-param/default-param.ino"
void setup() {
    func(11);
}
void loop() {}
void func(int xyzzy = 7) {}

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

Процесс сборки

Процесс сборки-это довольно уродливый... процесс... который очищает выходные данные компилятора и генерирует ctags для создания путей включения и пытается генерировать прямые ссылки на вещи. Иногда он просто ошибается. Я не уверен, в чем именно заключается ошибка в процессе сборки, но, вероятно, это просто ошибка, вызванная вызовом необъявленной функции с соответствующей записью в ctags. Вы можете попробовать прочитать документацию по процессу сборки, чтобы понять это. В конечном счете, однако, вам, возможно, придется прочитать источник arduino-cli/arduino-builder, чтобы добраться до точной причины.

Файлы, не относящиеся к.ino (и не относящиеся к.pde), более или менее проходят через процесс сборки невредимыми. Итак, если вам действительно нужны аргументы по умолчанию, вы можете использовать файл and .h для прототипа/объявления функции и файл .cpp для ее тела и следовать обычным правилам C++.

Использование вашей собственной декларации

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

void func(int xyzzy = 7);

void setup() {
    func(11);
}
void loop() {}
void func(int xyzzy) {}

Выход:

#include <Arduino.h>
#line 1 "/tmp/default-param/default-param.ino"
void func(int xyzzy = 7);

#line 3 "/tmp/default-param/default-param.ino"
void setup();
#line 6 "/tmp/default-param/default-param.ino"
void loop();
#line 7 "/tmp/default-param/default-param.ino"
void func(int xyzzy);
#line 3 "/tmp/default-param/default-param.ino"
void setup() {
    func(11);
}
void loop() {}
void func(int xyzzy) {}

Как вы можете видеть, он генерирует прото-тип по какой-то причине. Но не тот, который конфликтует с вашим собственным.


Вероятно, лучше, если вы хотите использовать аргументы по умолчанию, чтобы просто использовать заголовки и файл .cpp для тех функций, которые имеют их, чтобы вы не подвергались изменениям в способности arudino-cli/arduino-builder обрабатывать их.

,

Решение скрыто в ответе: «Вы можете просто сделать для этого собственное заявление». Предложение: переместиться наверх или добавить TLDR вверху., @Mathieu K.

Вероятно, когда я писал это, я воспринял *"или если я поставлю функцию мерцания перед циклом"* как означающее, что у них уже есть решение, и они задавались вопросом *почему*, так что TLDR - это скорее почему-TLDR*" Это просто неспособность процесса сборки Arduino генерировать прототипы»*, а не как-TLDR. Они не были явными в вопросе, поэтому оба покрыты. Если вы говорите, что нашли это полезным, но вам не понравилось читать до конца, конечно, я посмотрю, не смогу ли я рассмотреть часть как раньше., @timemage