Как прописать параметры функции по умолчанию

Densl
Offline
Зарегистрирован: 28.11.2018

Как известно ардуина сама объявляет функции. Соответственно если я хочу вставить параметр по умолчанию в имплементацию myFuncе(int x = 1), и воспользоваться им вызвав myFunct(), то получаю ошибку "myFunct() was not declared in this scope". Как сделать чтобы в ino файле таких проблем не было?

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Сделать заголовочный файл *.h, в котором описать прототип функции с параметром по умолчанию. Положить рядом с *.ino. Как-то так:

1. Объявление функции:

// файл function.h
#pragma once

#include <Arduino.h>

void myFynction(int param=1);

2. Определение функции:

// файл function.cpp

#include "function.h"

void myFynction(int param)
{
 // bla bla
}

3. *.ino файл:

#include "function.h"

void setup()
{
  myFunction();
}

vid loop() {}

 

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

Densl пишет:

то получаю ошибку "myFunct() was not declared in this scope".

эта ошибка никак не связана с параметрами по умолчанию, ищите другие ошибки

а что касается "ардуина сама обьявляет" - вам ничто не мешает обьявить функцию самому с нужными парметрами

Densl
Offline
Зарегистрирован: 28.11.2018

b707 пишет:

Densl пишет:

то получаю ошибку "myFunct() was not declared in this scope".

эта ошибка никак не связана с параметрами по умолчанию, ищите другие ошибки

а что касается "ардуина сама обьявляет" - вам ничто не мешает обьявить функцию самому с нужными парметрами

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

Densl
Offline
Зарегистрирован: 28.11.2018

DIYMan пишет:

Сделать заголовочный файл *.h, в котором описать прототип функции с параметром по умолчанию. Положить рядом с *.ino.

Спасибо, просто думал может попроще способ есть. Из-за одной функции файл создавать как-то странно выглядит.

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

Densl пишет:

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

что-то вы не так делаете, у меня все компилируется внутри одного скетча

void foo (int x =0) {
  Serial.print(x);
}

void setup() {
 Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  foo();
}

Скетч использует 1 962 байт (6%) памяти устройства. Всего доступно 30 720 байт.
Глобальные переменные используют 182 байт (8%) динамической памяти, оставляя 1 866 байт для локальных переменных.

Ардуино 1.6.12

 

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

Densl, вы функцию-то описываете, надеюсь, ДО использования? - такая ошибка как у вас. будет если описать функцию ниже (по коду) ее первого появления в программе

Densl
Offline
Зарегистрирован: 28.11.2018

b707 пишет:

Densl пишет:

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

что-то вы не так делаете, у меня все компилируется внутри одного скетча

void foo (int x =0) {
  Serial.print(x);
}

void setup() {
 Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  foo();
}

Скетч использует 1 962 байт (6%) памяти устройства. Всего доступно 30 720 байт.
Глобальные переменные используют 182 байт (8%) динамической памяти, оставляя 1 866 байт для локальных переменных.

Ардуино 1.6.12

 

Ха, прикольно. Попробовал я ваш пример и откомпилировался. Потом перенес функцию foo за loop и та же самая ошибка.

 

void setup() {

  Serial.begin(9600);

}



void loop() {

  // put your main code here, to run repeatedly:

  foo();

}

void foo (int x = 0) {
  Serial.print(x);

}

exit status 1
'foo' was not declared in this scope

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

Densl пишет:

Ха, прикольно. Попробовал я ваш пример и откомпилировался. Потом перенес функцию foo за loop и та же самая ошибка.

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

Densl
Offline
Зарегистрирован: 28.11.2018

b707 пишет:

Densl пишет:

Ха, прикольно. Попробовал я ваш пример и откомпилировался. Потом перенес функцию foo за loop и та же самая ошибка.

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

Ну так объявляю ее не я а Ардуина. Она должна пробежать по коду, найти все функции и объявить их заранее, но как-то странно это делает.

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

Densl пишет:

Ну так объявляю ее не я а Ардуина. Она должна пробежать по коду, найти все функции и объявить их заранее, но как-то странно это делает.

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

Лучше вообще не рассчитывать на эти костыли и делать все в соответвии с правилами языка. Ведь это совсем не трудно - поместить описание функции в начале кода?

Densl
Offline
Зарегистрирован: 28.11.2018

b707 пишет:

Densl пишет:

Ну так объявляю ее не я а Ардуина. Она должна пробежать по коду, найти все функции и объявить их заранее, но как-то странно это делает.

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

Лучше вообще не рассчитывать на эти костыли и делать все в соответвии с правилами языка. Ведь это совсем не трудно - поместить описание функции в начале кода?

Не трудно когда функция одна и маленькая. А если проект уже овер 2000 строк то не хотелось бы чтобы setup и loop были в конце. Долго скролить. В общем подключил h файл с объявлением и все заработало.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Densl пишет:

Не трудно когда функция одна и маленькая. А если проект уже овер 2000 строк то не хотелось бы чтобы setup и loop были в конце. Долго скролить. 

Вот именно поэтому я и описал вариант с разнесением по разным файлам ;) Структурирование - наше всё.

sadman41
Offline
Зарегистрирован: 19.10.2016

С проектом в овер 2000 пора подумать и о душе... То есть - о структурировании функционала и разноса его по другим файлам. А там уже и инклюды заголовочников само-собой рисовать придется и проблема рассосётся.

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

Densl пишет:

Не трудно когда функция одна и маленькая. А если проект уже овер 2000 строк то не хотелось бы чтобы setup и loop были в конце. Долго скролить.

повторяю - изучайте синтаксис. Можно оставить функцию в конце кода, если вам так нравится, а вперед вынести только обьявление:

void foo (int x =0);

void setup() {
 Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  foo();
}

void foo (int x ) {
  Serial.print(x);
}

так тоже компилируется

Densl
Offline
Зарегистрирован: 28.11.2018

Что лучше INO или CPP для вспомогательных файлов?

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

Densl пишет:

Что лучше INO или CPP для вспомогательных файлов?

по идее файл INO в ардуино-проекте должен быть один. Другие могут быть .h и .cpp. Кстати, в большинстве случаев можно и обьявление и имплементацию класть в файлы .h - так получается проще

Densl
Offline
Зарегистрирован: 28.11.2018

b707 пишет:

Densl пишет:

Что лучше INO или CPP для вспомогательных файлов?

Кстати, в большинстве случаев можно и обьявление и имплементацию класть в файлы .h - так получается проще

В общем дополнительные CPP  и INO файлы нужны больше для приличия в среде ардуино. Все можно делать в *.h файле. Тогда объявление = имплементация функции.

sadman41
Offline
Зарегистрирован: 19.10.2016

Один хидер может быть включен более, чем в один .cpp и при компиляции начнется оверхед и иные неприятные эффекты. Поэтому, если функция не inline, гораздо прагматичней выносить её в единожды компилируемый юнит(.cpp/.c), а объявлениями в .h давать знать другим компилируемым юнитам, что в объектном коде уже будет такая-то функция с такими-то параметрами. Штоп они не нервничали, так скыть.

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

Densl пишет:

В общем дополнительные CPP  и INO файлы нужны больше для приличия в среде ардуино.

не надо поспешных выводов. Главная разница в том, что .h файл включается непосредственно в тело программы, а .cpp компилируется отдельно.  Соответвенно, в .cpp модуле могут быть переменные и методы уровня файла. а в .h - нет. Как только вы начнете активно делить проект на отдельные файлы (например, в моих типичных ардуино проектах обычно 5-15 исходных файлов) - вы довольно быстро разберетесь, когда и какие файлы нужны...

Densl
Offline
Зарегистрирован: 28.11.2018

sadman41 пишет:

Один хидер может быть включен более, чем в один .cpp и при компиляции начнется оверхед и иные неприятные эффекты.

Ну а что мешает написать конструкцию #ifndef .. #define ... #endif

sadman41 пишет:
Поэтому, если функция не inline, гораздо прагматичней выносить её в единожды компилируемый юнит(.cpp/.c), а объявлениями в .h давать знать другим компилируемым юнитам, что в объектном коде уже будет такая-то функция с такими-то параметрами. Штоп они не нервничали, так скыть.

Х.з как в ардуино реализованы inline, но похоже он тут мало кого беспокоит. Можно еще про Ассемблер вспомнить, что он быстрее работает чем inline

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

Densl пишет:

Х.з как в ардуино реализованы inline, но похоже он тут мало кого беспокоит. Можно еще про Ассемблер вспомнить, что он быстрее работает чем inline

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

Densl
Offline
Зарегистрирован: 28.11.2018

Я с вами разобрался. Теперь понятно что и как работает. Заголовочные файлы наше всё!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Densl пишет:
Я с вами разобрался. Теперь понятно что и как работает. Заголовочные файлы наше всё!

Но даже если "Заголовочные файлы наше всё!" то объявление и реализацию желательно разделить внутри .h файла.

Densl
Offline
Зарегистрирован: 28.11.2018

qwone пишет:

Densl пишет:
Я с вами разобрался. Теперь понятно что и как работает. Заголовочные файлы наше всё!

Но даже если "Заголовочные файлы наше всё!" то объявление и реализацию желательно разделить внутри .h файла.


Ну тут же b707 в самом первом примере показывал как вставить функцию с параметрами по умолчанию чтобы всё заработало. Тогда по-сути вставка include ... как раз таки и добавляет строчки из h файла сразу же после себя. Или я чего то не догоняю?

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

Цитата:

Но даже если "Заголовочные файлы наше всё!" то объявление и реализацию желательно разделить внутри .h файла.

Вредный совет. Убедиться в том, что так делать нельзя - легко. Положите а директорию "a" три такие файла

a.ino

#include "f.h"

void setup(void) {
	Serial.begin(57600);
	pa.printA();
	pa.printB();
}
void loop(void){
}

f1.cpp

#include "f.h"

abc pa;

и f.h

#include <Arduino.h>

#define QCODE

#ifdef QCODE

	struct abc {
		void printA(void);
		void printB(void);
	};
	
	void abc::printA(void) { Serial.println("A"); }
	void abc::printB(void) { Serial.println("B"); }

#else

	struct abc {
		void printA(void) { Serial.println("A"); }
		void printB(void) { Serial.println("B"); }
	};

#endif

extern abc pa;

Нет возражений, что если в последнем оставить всё как есть, то будет компилироваться "как посоветовали" (с раздельным описанием и имплементацией), а если строку №3 закомментировать, то будет "всё вместе" - описание и имплементация тут же.

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

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

Densl пишет:
sadman41 пишет:

Один хидер может быть включен более, чем в один .cpp и при компиляции начнется оверхед и иные неприятные эффекты.

Ну а что мешает написать конструкцию #ifndef .. #define ... #endif

Ну, и чем и как это поможет?
Densl пишет:

Х.з как в ардуино реализованы inline, но похоже он тут мало кого беспокоит. Можно еще про Ассемблер вспомнить, что он быстрее работает чем inline

Проблема в том, что для Вас всё - ХЗ. Изучайте, узнавайте, чтобы было не ХЗ, а DenslЗ

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Densl пишет:
Теперь понятно что и как работает. Заголовочные файлы наше всё!
Если понятно, то вот тебе упражнение для самопроверки: объясни, что не так в #25 и почему в одном случае работает, а в другом - нет.

Densl
Offline
Зарегистрирован: 28.11.2018

Я думаю компилятор воспринимает это как перегрузку объявления и входит в ступор.

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

Densl пишет:
Я думаю компилятор воспринимает это как перегрузку объявления и входит в ступор.

Неверно думаете.

Значит, всё-таки, не совсем

Densl пишет:
понятно что и как работает

Постарайтесь разобраться, а если что - спрашивайте.

Densl
Offline
Зарегистрирован: 28.11.2018

Ну тогда 2 раза включается в cpp и ino файл что и создаёт конфликт передекларирования.

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

Это ближе к делу.

А как поправить, если таки хочется оставить их в .h и отдельно от описания класса (чтобы описание класса не перегружать)?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Вот блин. Я этого тоже нинаю. Если у мня есть в .h файле описание класса, я могу его имплементацию написать там же. Но если у мня есть независимые от класса функции, приходится их реализацию делать в .cpp файле и избежать этого я не могу, ибо не знаю как. С# привил мне привычку делать все в одном файле, а с С++ я так сделать не могу ( ну или нинаю как). :-)

astwo
Offline
Зарегистрирован: 10.07.2019

Разумеется их описывать в одном h файле сделав защиту от повторного включения что функции, что классы. qwone давно так делает.

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

Не, дед, ну, в простейшем случае - также как в С# - писать тела функция прямо в объявлении класса (как в #25 при закомментированной строке №3 и всё скушается). А вот если сильно хочется вынести их за класс (как в квонокоде), то, да, проблема. Решить можно, если их явно объявить inline (кстати, если писать их прямо в классе, то они inline по умолчанию), но это палка с двумя концами. Он (компилятор) ведь сдуру может послушаться и впрямь сделать их inline, т.е. пихать код везде где вызываются. Если вызовов немного и это не страшно, то это решение.

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

DetSimen пишет:

Вот блин. Я этого тоже нинаю. Если у мня есть в .h файле описание класса, я могу его имплементацию написать там же. Но если у мня есть независимые от класса функции, приходится их реализацию делать в .cpp файле и избежать этого я не могу, ибо не знаю как.

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

У меня в проектах. как правило, куча .h файлов и ни одного  .cpp ...

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

astwo пишет:
Разумеется их описывать в одном h файле сделав защиту от повторного включения что функции, что классы. qwone давно так делает.

Как это Вы собираетесь делать защиту от включения в разные файлы? Проблема-то возникает когда они в разные включаются. А то, что Квон так делает - так он много чего делает. Попробуйте включить его quonelib в два разных cpp файла и посмотрите, как оно у него замечательно работает.

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

b707 пишет:
Главное - избежать включения этого заголовка дважды в один и тот же компилируемый файл...
Проблема не во включении в один и тот же файл, а во включении в разные файлы. В них окажется функция с тем же именем (на самом деле, просто точно такая же). Чтобы функция при этом не вызвала конфликта "дважды определена" на этапе сборки, она должна быть либо static, либо inline. В обоих случаях она будет жрать место в коде каждый раз, когда включается.

astwo
Offline
Зарегистрирован: 10.07.2019

Квонокод нормальное решение, но в случае если в программе не заведутся всякие файлы. cpp. Так что или так или так.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

astwo пишет:
Квонокод нормальное решение, но в случае если в программе не заведутся всякие файлы. cpp. Так что или так или так.

Топором тоже можно операции на мозг делать. Правда, только однократно.

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

astwo пишет:
Квонокод нормальное решение, но в случае если в программе не заведутся всякие файлы. cpp
Если файл один, то да, можно и так. Только напрасно он пихает это решение в библиотеки. Библиотека - она по определению должна быть универсальной и не зависеть от того сколько файлов в программе. Впрочем, это его дело и тех, кто намерен его библиотеками пользоваться. Я к таковым не отношусь. 

astwo
Offline
Зарегистрирован: 10.07.2019

Нет у qwone библиотек, есть просто подключаемые файлы. Так что вопрос стоит сколько файлов кидать в скетч.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

https://github.com/DetSimen/Arduino_TimerList

подскажете, как в один .h файл улажицца? Функции в .cpp к классу не относюца. 

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

astwo пишет:
Нет у qwone библиотек, есть просто подключаемые файлы. Так что вопрос стоит сколько файлов кидать в скетч.

Если честно, я не понимаю, что Вы пытаетесь доказать. Возьмите qwonelib.h, включите её include'ом в .ino файл и в .cpp файл в том же проекте и чтобы она в обоих файла реально использовалась (как сделано в #25) и покажите мне, что всё замечательно компилируется и работает. Тогда я, возможно, пойму. Сделаете? Тогда поговорим. 

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

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

astwo пишет:
Разумеется их описывать в одном h файле сделав защиту от повторного включения что функции, что классы. qwone давно так делает.

Как это Вы собираетесь делать защиту от включения в разные файлы? Проблема-то возникает когда они в разные включаются. А то, что Квон так делает - так он много чего делает. Попробуйте включить его quonelib в два разных cpp файла и посмотрите, как оно у него замечательно работает.

м.б. использовать namespace? 

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

DetSimen пишет:

подскажете, как в один .h файл улажицца? Функции в .cpp к классу не относюца. 

функции к классу не относятся, но совсем независимыми их не назовешь - в них методы класса вызываются.

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

DetSimen пишет:
как в один .h файл улажицца?
Где взять Consts.h ?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

b707 пишет:

DetSimen пишет:

подскажете, как в один .h файл улажицца? Функции в .cpp к классу не относюца. 

функции к классу не относятся, но совсем независимыми их не назовешь - в них методы класса вызываются.

Да. :-)

Именна. :-)

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

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

b707 пишет:
Главное - избежать включения этого заголовка дважды в один и тот же компилируемый файл...
Проблема не во включении в один и тот же файл, а во включении в разные файлы.

да, согласен. Я. как правило, все .h файлы проекта включаю только один раз - в центральный модуль .ino или .cpp

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

Так, дед, Где взять Consts.h ?

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

b707 пишет:

да, согласен. Я. как правило, все .h файлы проекта включаю только один раз - в центральный модуль .ino или .cpp

Ну, как, а если он нужен? Если в этом .h описан какой-нить класс, то его необходимо включать во все .cpp в которых этот класс используется. Иначе-то никак.