Об умении готовить

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

Мужики, а вот скажите, кого-нибудь, акромя меня ещё достали вопли говнокодеров типа: «Я как-то попробовал написать программу с ООП – такой говнокодище!!! В топку этот ООП!!! Он не применим на МК!». Ума на то, чтобы понять, что это они сами наговнокодили, что говнокод не зависит ни от языка, ни от парадигмы программирования, но зависит исключительно от «прогера» у этих граждан обычно не хватает. Толком объяснить, чем же так плох ООП они тоже не могут ввиду отсутствия знаний. Зато вони и воплей от них …

В общем, достало меня это дело и решил я посмотреть насколько же ужасно неэффективен ООП. Для этого я выбрал задачу. Не ахти какую сложную (чтобы пример на тысячи строк не раздулся), но и не совсем тривиальную, чтобы и наследование пригодилось, и переопределение – в общем ООП'овские фенечки.

Задача такая: у меня есть подсвечиваемые кнопки (кому нужны – могу дать ссылку на али). Это обычные тактовые кнопки, но со встроенным светодиодом. Светодиод никак не соединён с ногами кнопки и управляется независимо. Задача: написать класс CLedButton, который постоянно держит светодиод включённым пока кнопка нажата и выключенным, когда она не нажата и, с помощью этого класса, управлять одновременно несколькими (в моём примере – тремя) кнопками.

Ну, что, как пишут в толстых книжках про ООП, нужна иерархия классов от пина до нашей подсвечиваемой кнопки. Всего у меня получилось семь классов. Иерархия выглядит примерно вот так:

Их исходный код выглядит примерно так (файл "oopsample.h") выглядит вот так:

#ifndef	OOPSAMPLE_H
#define	OOPSAMPLE_H

//
//	Класс для GPIO с константным номерам пина
//
//	Использование:
//		CPin<номер пина> myPin; // объявление
//		myPin.mode(OUTPUT); // задать направление
// 	myPin = true; // установить в HIGH
// 	myPin = false; // установить в LOW
// 	const bool pinState = myPin; // опросить состояние
//
template <const int8_t pin> 
class CPin {
public:
	inline void mode(const uint8_t _mode) const { pinMode(pin, _mode); }
	inline bool operator = (const bool state) const { digitalWrite(pin, state); return state; }
	inline operator bool() const { return digitalRead(pin); }
};

//
//	Класс для z-state GPIO с константным номерам пина
//	Полностью наследует функциональность CPin + автоматически
//	устанавливает mode(INPUT) в конструкторе
//
//	Использование:
//		CInputPin<номер пина> myPin; // объявление
//		остальное также, как у CPin
//
template <const int8_t pin> 
class CInputPin : protected CPin<pin> {
public:
	inline CInputPin(void) { this->mode(INPUT); }
	inline bool operator = (const bool state) const { return * reinterpret_cast<const CPin<pin> *>(this) = state; }
	inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const CPin<pin> *>(this)); }
};

//
//	Класс для GPIO в режиме OUTPUT с константным номерам пина
//	Полностью наследует функциональность CPin + автоматически
//	устанавливает mode(OUTPUT) в конструкторе
//
//	Использование:
//		COutputPin<номер пина> myPin; // объявление
//		остальное также, как у CPin
//
template <const int8_t pin> 
class COutputPin : protected CPin<pin> {
public:
	inline COutputPin(void) { this->mode(OUTPUT); }
	inline bool operator = (const bool state) const { return * reinterpret_cast<const CPin<pin> *>(this) = state; }
	inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const CPin<pin> *>(this)); }
};

//
//	Класс для GPIO в режиме INPUT_PULLUP с константным номерам пина
//	Полностью наследует функциональность CPin + автоматически
//	устанавливает mode(INPUT_PULLUP) в конструкторе
//
//	Использование:
//		CInputPullUpPin<номер пина> myPin; // объявление
//		остальное также, как у CPin
//
template <const int8_t pin> 
class CInputPullUpPin : protected CPin<pin> {
public:
	inline CInputPullUpPin(void) { this->mode(INPUT_PULLUP); }
	inline bool operator = (const bool state) const { return * reinterpret_cast<const CPin<pin> *>(this) = state; }
	inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const CPin<pin> *>(this)); }
};

//
//	Класс для пина кнопки. 
// Кнопка - это GPIO в режиме INPUT_PULLUP
//	Переопределено преобразование к bool так,
//	чтобы true выдавалось, когда кнопка нажата
//	(т.е. когда на пине LOW)
//
//	Использование:
//		CButtonPin<номер пина> myPin; // объявление
//		остальное также, как у CPin, только при преобразовании
//		к bool возвращает инвертированное значение: true если
//		на пине LOW (нажата) и false если на пине HIGH (отпущена)
//
template <const int8_t pin> 
class CButtonPin : protected CInputPullUpPin<pin> {
public:
	inline operator bool() const { 
		return ! static_cast <bool> (* reinterpret_cast<const CPin<pin> *>(this));
	}
};

//
//	Класс для пина светодиода. 
// тот же пин в режиме OUTPUT, но у него есть
//	ещё один параметр - offState. Это состоние пина
//	при котором светодиод НЕ светится. В случае подключения
//	анодом к пину, а катодом к GND - offState должно быть false
//	В случае же подключения катодом к пину, а анодом к Vcc,
//	offState должно быть true.
//	Есть два метода turnOn и turnOff
//
//	Использование:
//		CLedPin<номер пина, true/false> myLed; // объявление
//		myLed.turnOn();	// зажечь
//		myLed.turnOff();	// погасить
//		остальное также, как у COutputPin
//
template <const int8_t pin, const bool offState> 
class CLedPin : protected COutputPin<pin> {
public:
	inline void turnOn(void) const { * this = !offState; }
	inline void turnOff(void) const { * this = offState; }
	inline bool operator = (const bool state) const { return * reinterpret_cast<const COutputPin<pin> *>(this) = state; }
	inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const COutputPin<pin> *>(this)); }
};

//
//	Класс для подсвечиваемой кнопки. 
// Наследует всю функциональность как от класса CButtonPin,
//	так и от класса CLedPin. Кроме того имеет метод run.
//	Если вызвать метов, то он приведёт подсветку в соостветсии 
//	с "нажатостью" кнопки. Нажата - светодиод светится.
//	При обявлении используются три парамтера. Первые два - от 
//	светодиода (класса CLedPin), а третий от кнопки (класса CButtonPin)
//	При этом нельзя напрямую доступаться до методов кнопки и светодиода
//	по отдельности.
//	Если данный класс епробразовать к bool, то будет true если кнопка нажата.
//
//	Использование:
//		CLedButton<номер пина светодиода, true/false, номер пина кнопки> myHBtn; // объявление
//		myHBtn.run();	// привести светодиод в соответствие с "нажатостью" кнопки
//
template <const int8_t ledPin, const bool offState, const int8_t btnPin> 
class CLedButton : protected CLedPin<ledPin, offState>, CButtonPin<btnPin>  {
public:
	inline void run(void) const {
		* reinterpret_cast<const CPin<ledPin> *>(this) = 
			static_cast<bool>(* reinterpret_cast<const CButtonPin<btnPin> *>(this)); 
	}
	inline operator bool() const { 
		return static_cast <bool> (* reinterpret_cast<const CButtonPin<btnPin> *>(this));
	}
};

#endif	//	OOPSAMPLE_H

Как видите, здесь есть и наследование (одиночное и множественное), и переопределение, и шаблоны – каждой твари по паре. Использование и параметры классов прокомментированы. Сами классы крохотные – единицы строк. Подробно расписывать что там и как, я не буду. Для знающих – не нужно, а для незнающих – тут надо полстрауструпа переписать.

Допустим, что кнопки подключены на пины («светодиод»/«собственно кнопка») 13/5, 12/4 и 11/3. Тогда проверочный код для поставленной задачи получается примерно как в левой части таблицы ниже. В правой части я привёл точно такой же по функциональности код, но без богомерзкого ООП – на тёплом и лапмовом. Компилировалось всё это добро в IDE версии 1.8.9 для платы Uno. Любой желающий может скомпилировать сам и убедиться в правильности цифр, приведённых после каждого кода.

#include "oopsample.h"

void setup(void) {
	CLedButton <13, LOW, 5> highlightedButton1;
	CLedButton <12, LOW, 4> highlightedButton2;
	CLedButton <11, LOW, 3> highlightedButton3;
	
	while (true) {
		highlightedButton1.run();
		highlightedButton2.run();
		highlightedButton3.run();
	}
}

void loop(void) {}
/*
Скетч использует 1008 байт (3%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 9 байт (0%)
*/
void setup(void) {
 	pinMode(13, OUTPUT);
 	pinMode(12, OUTPUT);
 	pinMode(11, OUTPUT);
 	pinMode(5, INPUT_PULLUP);
 	pinMode(4, INPUT_PULLUP);
 	pinMode(3, INPUT_PULLUP);
 	
	while (true) {
		digitalWrite(13, ! digitalRead(5));
		digitalWrite(12, ! digitalRead(4));
		digitalWrite(11, ! digitalRead(3));
	}
}

void loop(void) {}
/*
Скетч использует 1008 байт (3%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 9 байт (0%)
*/

Как видите, памяти этот жООП сожрал немерянно! Тёплый ламповый код кушает всего лишь 1008/9 байтиков, а это богомерзкое жООПище размахнулось аж на 1008/9 байтищев!!!

А, может, оно не память жрёт, а быстродействие? Может, она там так тормозить будет, что мама не горюй? Проверим? Хотя, … я то знаю, что коды идентичны абсолютно. А те, кто этого не понял, проверяйте сами. Это несложно, поставьте вместо бесконечного цикла какой-нибудь итераций на 10000. Замерьте время миллисом и убедитесь что скорости выполнения абсолютно равны.

Так что, знайте, мужики: если Вам вешают, что ООП жрёт память, тормозит, говнокодит и «ваще в топку», это означает, что либо этот человек врёт как сивый мерин, либо просто не умеет этот ООП готовить. Скорее всего - второе. Перед Вами просто безграмотный говнокодер, который скрывает своё неумение программировать высокомерным: «в дерьмо не лезу». Ну и Вы к нему не лезьте. Чище воздух будет.

Разумеется, нельзя не признать, что говнокода с использованием ООП в сети полно. Но ничуть не больше, чем говнокода с использованием любой другой технологии прогрммрования! Говнокодит не среда – говнокодит программист. И таких специалистов у нас пруд пруди. Уверяю Вас, что человек, написавший (безо всякого ООП, заметьте!!!) отлитый в граните «#define TSC_PERIOD (1000/1024)», способен наговнокодить на любом языке, в любой системе и в любой технологии программирования. Даже не сомневайтесь!

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

да ну... три кнопочки и три светодиода и кода в 1000 байт, что-то не то в этой консерватории IDE

b707
Онлайн
Зарегистрирован: 26.05.2017

ua6em пишет:

да ну... три кнопочки и три светодиода и кода в 1000 байт, что-то не то в этой консерватории IDE

это вы еще не пробовали этот код собрать для контроллера  ECП8266 или СТМ32

 

2 Ворота - красиво, но бесполезно. Фанатизм непобедим.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Ворота пишет:

памяти этот жООП сожрал немерянно! Тёплый ламповый код кушает всего лишь 1008/9 байтиков, а это богомерзкое жООПище размахнулось аж на 1008/9 байтищев!!!

Малацца! Мне всё лень было...

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

b707 пишет:

ua6em пишет:

да ну... три кнопочки и три светодиода и кода в 1000 байт, что-то не то в этой консерватории IDE

это вы еще не пробовали этот код собрать для контроллера  ECП8266 или СТМ32

Это незаконченный роман про ассемблер, которым "всё в три строки делается". 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

b707 пишет:

ua6em пишет:

да ну... три кнопочки и три светодиода и кода в 1000 байт, что-то не то в этой консерватории IDE

это вы еще не пробовали этот код собрать для контроллера  ECП8266 или СТМ32

Это незаконченный роман про ассемблер, которым "всё в три строки делается". 

берём пустой скетч, компилируем, получаем 444 байта и 9 байт ОЗУ, смотрим и пишем по аналогии на ассемблере (так как для атмеги оного не знаю, пишу по аналогии)

0000 jmp 010
...
0010 nop
0011 jmp 010

И?
 

 

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

ua6em пишет:

берём пустой скетч, компилируем, получаем 444 байта и 9 байт ОЗУ, смотрим и пишем по аналогии на ассемблере (так как для атмеги оного не знаю, пишу по аналогии)

0000 jmp 010
...
0010 nop
0011 jmp 010

И?

И? Вот у Ворот законченная мысль - читать прятно, а у Вас она о чём? Накидали джампов с нопами - зачем? Задача - зажечь светодиоды в зависимости от нажатых кнопок.

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

ua6em пишет:

И?

Ни грамма не "и". Теперь пробуем в этот пустой код хоть что-нибудь добавить. И сразу выясняется, у Вас-то он и впрямь пустой, а вот в IDE там уж и миллис тикает, и ШИМ сконфигурирован и много чего ещё сделано.

------------------

Ворота,

а чё шаблоны с самого низу тянутся? Если их наоборот на самый верх вытащить, то не нужна будет чёртова уйма переопределений со страшными reinterpret_cast'ами.

И ещё по картинке. Видимо, CLedPin всё же от COutputPin наследуется. В коде так, по крайней мере :)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

И? Вот у Ворот законченная мысль - читать прятно, а у Вас она о чём? Накидали джампов с нопами - зачем? Задача - зажечь светодиоды в зависимости от нажатых кнопок.

так я не программист, думаю найдётся на форуме, кто сделает тоже самое на чистом С )))
PS так как сдаётся мне, что и там и там ООП используется

Sindbad
Offline
Зарегистрирован: 08.12.2015

Ворота пишет:

Как видите, здесь есть и наследование (одиночное и множественное), и переопределение, и шаблоны – каждой твари по паре.

...

Как видите, памяти этот жООП сожрал немерянно! Тёплый ламповый код кушает всего лишь 1008/9 байтиков, а это богомерзкое жООПище размахнулось аж на 1008/9 байтищев!!!

Каждой, да не каждой. Главная фишка ООП - полиморфизм времени исполнения. Все остальное компилируется не менее эффективно чем чистый Си. Да по сути от чистого Си и не отличается.

Вот статья с описанием проблем ООП для Ардуино: 

https://habr.com/ru/company/amperka/blog/264041/

 

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

Sindbad пишет:
Главная фишка ООП
Там все фишки равноправны - нету главных.

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

ua6em пишет:

так я не программист, думаю найдётся на форуме, кто сделает тоже самое на чистом С )))

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

Sindbad
Offline
Зарегистрирован: 08.12.2015

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

Там все фишки равноправны - нету главных.

Это все софистика.

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

Sindbad пишет:

Вот статья с описанием проблем ООП для Ардуино: 

 

https://habr.com/ru/company/amperka/blog/264041/

Ну, автор почему-то выделил  три составлящие ООП. Непонятно, куда он дел абстрагирование, ну до Бог с ним. О его статье мы ещё поговорим.

Пока, давай определимся с понятиями.

То, что у меня - это ООП или не ООП? У меня используются три из четырёх составляющих. И показано, что при их использовании нет никаких накладных расходов, зато есть все плюсы - абстрагирование, наследование (даже множественное) и инкапсуляция. Считаю, что задача показать, что использовать ООП с его плюсами можно без накладных расходов выполнена.

Что же до виртуальных функций - ну так и говорите, что виртуальные функции дороги. Чего на весь ООП-то катить бочку? Тогда можно и о виртуальных функциях отдельно и особо поговорить. Там тоже есть свои приёмы. Совсем свести в ноль не получится, но если с умом делать, то всё там вполне приемлемо. Правда, виртуальные функции - настолько мощное средство. Я вот ещё ни разу не встречал реальной задачи на МК где они мне реально (действительно, до зарезу) понадобились бы.

Теперь о статье. Автор не совсем прав в утверждении, что таблица не может меняться. В том счмысле, что пока формально, вроде и прав ... но это противоречит вектору развития языка, а потому делать сейчас компилятор в эту сторону, чтобы через 1-2 выпуска стандарта огрести несовместимоть ... оно надо?. Но это сильно выходит за рамки разговора на любительском форуме. Добро пожаловать на CPPCon. Ближайшая - в сетнябре в Колорадо. Там это можно обсудить. 

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

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

а чё шаблоны с самого низу тянутся? Если их наоборот на самый верх вытащить

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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

ua6em пишет:

так я не программист, думаю найдётся на форуме, кто сделает тоже самое на чистом С )))

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

не получится ...это у меня в крови )))
Вот даже Евгений не всё перечислил, что включается по умолчанию, а если оно вообще не потребуется в программе? Сходство с изделиями Микрософт, тот же эксель к примеру, 99,9% пользователей  даже 1% функциола не используют, но, заплачено за всё...

А IDE вообще-то не критикую, я восторгаюсь уровнем вхождения в этот мир... (..., ..., гони трояк) )))

 

Алексей.
Алексей. аватар
Онлайн
Зарегистрирован: 02.02.2018

Немножко иной взгляд на управление пинами.
Иногда не требуется инициализировать для одного класса (объекта) сразу два пина, для чтения и для записи.
Какие-то нужны для записи, а какие-то для чтения и ни никак не связаны.
Хочется к пинам обращаться через индексный оператор, ну и как выше реализовано у ТС (спасиб, было желание ответить на ООП, но холивар тухлый, а тут просто подарок), устанавливать пин - через вызов оператора присваивания от логического типа, читать пин - через вызов оператора приведения типа int

#define USE_OOP

#ifdef USE_OOP

class DPin {
  
public:
  
  class Pin {
  
  public:
  
    /**
     * Конструктор
     * @param pin номер пина
     */
    inline Pin(uint8_t pin) {
      this->pin = pin;
    }

    /**
     * Оператор присваивания
     * Для объекта источника выполняет чтение пина,
     * затем для объекта получателя выполняет запись полученного значения при чтении
     * и копирует номер пина источника, так до кучи
     * @param rhs ссылка на объект источника
     * @return ссылка на собственный экземпляр
     */
    inline Pin& operator = (Pin& rhs) {
      digitalWrite(this->pin, digitalRead(rhs.pin));
      this->pin = rhs.pin;
      return *this;
    }
    /**
     * Оператор приведения типа, выполняет чтение состояния пина.
     * @return состояние пина
     */
    inline operator int () const {
      return digitalRead(this->pin);
    }
    /**
     * Оператор присваивания, выполняет запись значения для пина
     * @param value значение для записи
     * @return оригинальное значение value
     */
    inline bool operator = (bool value) {
      digitalWrite(this->pin, value);
      return value;
    }

    uint8_t pin;
  };
  
  /**
   * Инициализация режима пина
   * @param pin номер пина
   * @param mode режим
   * @return ссылка на собственный экземпляр, только для понтов
   */
  inline DPin& init(uint8_t pin, uint8_t mode) {
    pinMode(pin, mode);
    return *this;
  }

  /**
   * Индексный оператор
   * @param index номер пина
   * @return экземпляр DPin::Pin для которого будут
   *         выполняться операции приведения типа (обертка над digitalRead)
   *         и операции присваивания (обертка над digitalWrite)
   *
   */
  inline DPin::Pin operator[](int index) {
    return DPin::Pin(index);
  }
};
#endif

void setup(void) {
#ifdef USE_OOP
  DPin pins;
  pins.init(13, OUTPUT)
   .init(12, OUTPUT)
   .init(11, OUTPUT)
   .init(5, INPUT_PULLUP)
   .init(4, INPUT_PULLUP)
   .init(3, INPUT_PULLUP);

  while (true) {
    pins[13] = !pins[5];
    pins[12] = !pins[4];
    pins[11] = !pins[3];
  }
#else  
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(5, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  
  while (true) {
    digitalWrite(13, !digitalRead(5));
    digitalWrite(12, !digitalRead(4));
    digitalWrite(11, !digitalRead(3));
  }
#endif
}

void loop(void) {}

Результат сборки прежний Скетч использует 1008 байт (3%) памяти устройства. Всего доступно 32256 байт. Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт.

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

Спасибо, Алексей.,

по мне так примерно так и должно проходить обсуждение.

По решению: сейчас ООПофобы подтянутся и начнут тебя бить. Дело в том, что это при компиляции у тебя 9 байтов. А динамически создаются экземпляры, которые имеют поле uint8_t pin; которое отъедает аж целый байт (это же ужас!!!)!!! Этого тебе Архат не простит!

Кстати, видел вот такую библиотеку? Красиво сделано. Хотя, твой подход с индексами или IDE'шный с номерами мне нравится больше. Но, всё равно красиво - этого не отнять.

Beginer123
Offline
Зарегистрирован: 23.11.2018

Ворота, спасибо! Оформил в табличку то, что подлежит сравнению, так нагляднее:

Дополнительные затраты на улучшение

//
//  Класс для GPIO с константным номерам пина
//
//  Использование:
//    CPin<номер пина> myPin; // объявление
//    myPin.mode(OUTPUT); // задать направление
//  myPin = true; // установить в HIGH
//  myPin = false; // установить в LOW
//  const bool pinState = myPin; // опросить состояние
//
template <const int8_t pin> 
class CPin {
public:
  inline void mode(const uint8_t _mode) const { pinMode(pin, _mode); }
  inline bool operator = (const bool state) const { digitalWrite(pin, state); return state; }
  inline operator bool() const { return digitalRead(pin); }
};

//
//  Класс для z-state GPIO с константным номерам пина
//  Полностью наследует функциональность CPin + автоматически
//  устанавливает mode(INPUT) в конструкторе
//
//  Использование:
//    CInputPin<номер пина> myPin; // объявление
//    остальное также, как у CPin
//
template <const int8_t pin> 
class CInputPin : protected CPin<pin> {
public:
  inline CInputPin(void) { this->mode(INPUT); }
  inline bool operator = (const bool state) const { return * reinterpret_cast<const CPin<pin> *>(this) = state; }
  inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const CPin<pin> *>(this)); }
};

//
//  Класс для GPIO в режиме OUTPUT с константным номерам пина
//  Полностью наследует функциональность CPin + автоматически
//  устанавливает mode(OUTPUT) в конструкторе
//
//  Использование:
//    COutputPin<номер пина> myPin; // объявление
//    остальное также, как у CPin
//
template <const int8_t pin> 
class COutputPin : protected CPin<pin> {
public:
  inline COutputPin(void) { this->mode(OUTPUT); }
  inline bool operator = (const bool state) const { return * reinterpret_cast<const CPin<pin> *>(this) = state; }
  inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const CPin<pin> *>(this)); }
};

//
//  Класс для GPIO в режиме INPUT_PULLUP с константным номерам пина
//  Полностью наследует функциональность CPin + автоматически
//  устанавливает mode(INPUT_PULLUP) в конструкторе
//
//  Использование:
//    CInputPullUpPin<номер пина> myPin; // объявление
//    остальное также, как у CPin
//
template <const int8_t pin> 
class CInputPullUpPin : protected CPin<pin> {
public:
  inline CInputPullUpPin(void) { this->mode(INPUT_PULLUP); }
  inline bool operator = (const bool state) const { return * reinterpret_cast<const CPin<pin> *>(this) = state; }
  inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const CPin<pin> *>(this)); }
};

//
//  Класс для пина кнопки. 
// Кнопка - это GPIO в режиме INPUT_PULLUP
//  Переопределено преобразование к bool так,
//  чтобы true выдавалось, когда кнопка нажата
//  (т.е. когда на пине LOW)
//
//  Использование:
//    CButtonPin<номер пина> myPin; // объявление
//    остальное также, как у CPin, только при преобразовании
//    к bool возвращает инвертированное значение: true если
//    на пине LOW (нажата) и false если на пине HIGH (отпущена)
//
template <const int8_t pin> 
class CButtonPin : protected CInputPullUpPin<pin> {
public:
  inline operator bool() const { 
    return ! static_cast <bool> (* reinterpret_cast<const CPin<pin> *>(this));
  }
};

//
//  Класс для пина светодиода. 
// тот же пин в режиме OUTPUT, но у него есть
//  ещё один параметр - offState. Это состоние пина
//  при котором светодиод НЕ светится. В случае подключения
//  анодом к пину, а катодом к GND - offState должно быть false
//  В случае же подключения катодом к пину, а анодом к Vcc,
//  offState должно быть true.
//  Есть два метода turnOn и turnOff
//
//  Использование:
//    CLedPin<номер пина, true/false> myLed; // объявление
//    myLed.turnOn(); // зажечь
//    myLed.turnOff();  // погасить
//    остальное также, как у COutputPin
//
template <const int8_t pin, const bool offState> 
class CLedPin : protected COutputPin<pin> {
public:
  inline void turnOn(void) const { * this = !offState; }
  inline void turnOff(void) const { * this = offState; }
  inline bool operator = (const bool state) const { return * reinterpret_cast<const COutputPin<pin> *>(this) = state; }
  inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const COutputPin<pin> *>(this)); }
};

//
//  Класс для подсвечиваемой кнопки. 
// Наследует всю функциональность как от класса CButtonPin,
//  так и от класса CLedPin. Кроме того имеет метод run.
//  Если вызвать метов, то он приведёт подсветку в соостветсии 
//  с "нажатостью" кнопки. Нажата - светодиод светится.
//  При обявлении используются три парамтера. Первые два - от 
//  светодиода (класса CLedPin), а третий от кнопки (класса CButtonPin)
//  При этом нельзя напрямую доступаться до методов кнопки и светодиода
//  по отдельности.
//  Если данный класс епробразовать к bool, то будет true если кнопка нажата.
//
//  Использование:
//    CLedButton<номер пина светодиода, true/false, номер пина кнопки> myHBtn; // объявление
//    myHBtn.run(); // привести светодиод в соответствие с "нажатостью" кнопки
//
template <const int8_t ledPin, const bool offState, const int8_t btnPin> 
class CLedButton : protected CLedPin<ledPin, offState>, CButtonPin<btnPin>  {
public:
  inline void run(void) const {
    * reinterpret_cast<const CPin<ledPin> *>(this) = 
      static_cast<bool>(* reinterpret_cast<const CButtonPin<btnPin> *>(this)); 
  }
  inline operator bool() const { 
    return static_cast <bool> (* reinterpret_cast<const CButtonPin<btnPin> *>(this));
  }
};
оригинал ничего тут нет
Собственно для повышения читаемости этого
void setup(void) {
  CLedButton <13, LOW, 5> highlightedButton1;
  CLedButton <12, LOW, 4> highlightedButton2;
  CLedButton <11, LOW, 3> highlightedButton3;
  
  while (true) {
    highlightedButton1.run();
    highlightedButton2.run();
    highlightedButton3.run();
  }
}

void loop(void) {}
/*
Скетч использует 1008 байт (3%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 9 байт (0%)
*/
void setup(void) {
 	pinMode(13, OUTPUT);
 	pinMode(12, OUTPUT);
 	pinMode(11, OUTPUT);
 	pinMode(5, INPUT_PULLUP);
 	pinMode(4, INPUT_PULLUP);
 	pinMode(3, INPUT_PULLUP);
 	
	while (true) {
		digitalWrite(13, ! digitalRead(5));
		digitalWrite(12, ! digitalRead(4));
		digitalWrite(11, ! digitalRead(3));
	}
}

void loop(void) {}
/*
Скетч использует 1008 байт (3%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 9 байт (0%)
*/

 

В общем-то насколько стало больше дополнительного кода и насколько упростился setup() - очевидно.

Но, мне кажется. что если быть честным и не лукавить, то правую сторону надо улучшить средствами Си, например так:

Дополнительные затраты на улучшение

//
//  Класс для GPIO с константным номерам пина
//
//  Использование:
//    CPin<номер пина> myPin; // объявление
//    myPin.mode(OUTPUT); // задать направление
//  myPin = true; // установить в HIGH
//  myPin = false; // установить в LOW
//  const bool pinState = myPin; // опросить состояние
//
template <const int8_t pin> 
class CPin {
public:
  inline void mode(const uint8_t _mode) const { pinMode(pin, _mode); }
  inline bool operator = (const bool state) const { digitalWrite(pin, state); return state; }
  inline operator bool() const { return digitalRead(pin); }
};

//
//  Класс для z-state GPIO с константным номерам пина
//  Полностью наследует функциональность CPin + автоматически
//  устанавливает mode(INPUT) в конструкторе
//
//  Использование:
//    CInputPin<номер пина> myPin; // объявление
//    остальное также, как у CPin
//
template <const int8_t pin> 
class CInputPin : protected CPin<pin> {
public:
  inline CInputPin(void) { this->mode(INPUT); }
  inline bool operator = (const bool state) const { return * reinterpret_cast<const CPin<pin> *>(this) = state; }
  inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const CPin<pin> *>(this)); }
};

//
//  Класс для GPIO в режиме OUTPUT с константным номерам пина
//  Полностью наследует функциональность CPin + автоматически
//  устанавливает mode(OUTPUT) в конструкторе
//
//  Использование:
//    COutputPin<номер пина> myPin; // объявление
//    остальное также, как у CPin
//
template <const int8_t pin> 
class COutputPin : protected CPin<pin> {
public:
  inline COutputPin(void) { this->mode(OUTPUT); }
  inline bool operator = (const bool state) const { return * reinterpret_cast<const CPin<pin> *>(this) = state; }
  inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const CPin<pin> *>(this)); }
};

//
//  Класс для GPIO в режиме INPUT_PULLUP с константным номерам пина
//  Полностью наследует функциональность CPin + автоматически
//  устанавливает mode(INPUT_PULLUP) в конструкторе
//
//  Использование:
//    CInputPullUpPin<номер пина> myPin; // объявление
//    остальное также, как у CPin
//
template <const int8_t pin> 
class CInputPullUpPin : protected CPin<pin> {
public:
  inline CInputPullUpPin(void) { this->mode(INPUT_PULLUP); }
  inline bool operator = (const bool state) const { return * reinterpret_cast<const CPin<pin> *>(this) = state; }
  inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const CPin<pin> *>(this)); }
};

//
//  Класс для пина кнопки. 
// Кнопка - это GPIO в режиме INPUT_PULLUP
//  Переопределено преобразование к bool так,
//  чтобы true выдавалось, когда кнопка нажата
//  (т.е. когда на пине LOW)
//
//  Использование:
//    CButtonPin<номер пина> myPin; // объявление
//    остальное также, как у CPin, только при преобразовании
//    к bool возвращает инвертированное значение: true если
//    на пине LOW (нажата) и false если на пине HIGH (отпущена)
//
template <const int8_t pin> 
class CButtonPin : protected CInputPullUpPin<pin> {
public:
  inline operator bool() const { 
    return ! static_cast <bool> (* reinterpret_cast<const CPin<pin> *>(this));
  }
};

//
//  Класс для пина светодиода. 
// тот же пин в режиме OUTPUT, но у него есть
//  ещё один параметр - offState. Это состоние пина
//  при котором светодиод НЕ светится. В случае подключения
//  анодом к пину, а катодом к GND - offState должно быть false
//  В случае же подключения катодом к пину, а анодом к Vcc,
//  offState должно быть true.
//  Есть два метода turnOn и turnOff
//
//  Использование:
//    CLedPin<номер пина, true/false> myLed; // объявление
//    myLed.turnOn(); // зажечь
//    myLed.turnOff();  // погасить
//    остальное также, как у COutputPin
//
template <const int8_t pin, const bool offState> 
class CLedPin : protected COutputPin<pin> {
public:
  inline void turnOn(void) const { * this = !offState; }
  inline void turnOff(void) const { * this = offState; }
  inline bool operator = (const bool state) const { return * reinterpret_cast<const COutputPin<pin> *>(this) = state; }
  inline operator bool() const { return static_cast<bool>(* reinterpret_cast<const COutputPin<pin> *>(this)); }
};

//
//  Класс для подсвечиваемой кнопки. 
// Наследует всю функциональность как от класса CButtonPin,
//  так и от класса CLedPin. Кроме того имеет метод run.
//  Если вызвать метов, то он приведёт подсветку в соостветсии 
//  с "нажатостью" кнопки. Нажата - светодиод светится.
//  При обявлении используются три парамтера. Первые два - от 
//  светодиода (класса CLedPin), а третий от кнопки (класса CButtonPin)
//  При этом нельзя напрямую доступаться до методов кнопки и светодиода
//  по отдельности.
//  Если данный класс епробразовать к bool, то будет true если кнопка нажата.
//
//  Использование:
//    CLedButton<номер пина светодиода, true/false, номер пина кнопки> myHBtn; // объявление
//    myHBtn.run(); // привести светодиод в соответствие с "нажатостью" кнопки
//
template <const int8_t ledPin, const bool offState, const int8_t btnPin> 
class CLedButton : protected CLedPin<ledPin, offState>, CButtonPin<btnPin>  {
public:
  inline void run(void) const {
    * reinterpret_cast<const CPin<ledPin> *>(this) = 
      static_cast<bool>(* reinterpret_cast<const CButtonPin<btnPin> *>(this)); 
  }
  inline operator bool() const { 
    return static_cast <bool> (* reinterpret_cast<const CButtonPin<btnPin> *>(this));
  }
};
/**
 * Кнопки с подсветкой.
 * ====================
 * 
 * Кнопка подтянута к питанию: нажата - замыкание на землю (LOW)
 * Встроенный светодиод управляется по аноду:
 * HIGH - горит, катод(-) на земле, резистор подтяжки на входе управления и аноде(+)
 */

/**
 * for SETUP()
 * настройка ножек пары "кнопка с подсветкой"
 */
void ledbtnSetup(uint8_t pLed, uint8_t pBtn, bool mode)
{
  pinMode((pBtn), INPUT_PULLUP);
  pinMode((pLed), OUTPUT);
  digitalWrite((pLed), (mode));
}
/**
 * Согласование состояния светодиода с нажатием кнопки:
 * нажата - светодиод включен, иначе - выключен
 */
void ledbtnRun(uint8_t pLed, uint8_t pBtn)
{
  digitalWrite(pLed, !digitalRead(pBtn));
}
Собственно итог повышения читаемости:
void setup(void) {
  CLedButton <13, LOW, 5> highlightedButton1;
  CLedButton <12, LOW, 4> highlightedButton2;
  CLedButton <11, LOW, 3> highlightedButton3;
  
  while (true) {
    highlightedButton1.run();
    highlightedButton2.run();
    highlightedButton3.run();
  }
}

void loop(void) {}
/*
Скетч использует 1008 байт (3%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 9 байт (0%)
*/
void setup() {
  ledbtnSetup(13, 4, LOW);
  ledbtnSetup(12, 3, LOW);
  ledbtnSetup(11, 2, LOW);

  do{
    ledbtnRun(13,4);
    ledbtnRun(12,3);
    ledbtnRun(11,2);
  }while(1);
}

void loop(){}
/*
 * Скетч использует 990 байт (3%) памяти устройства. Всего доступно 32256 байт.
 * Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт. */
 */

 

Ой .. оно ещё и меньше стало. Видимо что-то напутал, ну да ладно, не суть. Так наглядно видны затраты на борьбу со сложностью setup() и в общем-то каждый способен сделать свои выводы.

Спасибо.

Алексей.
Алексей. аватар
Онлайн
Зарегистрирован: 02.02.2018

Ворота пишет:
По решению: сейчас ООПофобы подтянутся и начнут тебя бить. Дело в том, что это при компиляции у тебя 9 байтов. А динамически создаются экземпляры, которые имеют поле uint8_t pin; которое отъедает аж целый байт (это же ужас!!!)!!! Этого тебе Архат не простит!
Про выделение памяти под класс, размером в один байт, я знаю, только молчу скромно.
А что касается использовать или нет то или иное решение определяет пока тот кто платит ;)

Задачка реализовать кодек, нечто, что обрабатывает поток данных.
1. Давайте сделаем на ООП, будет красиво и элегантно.
2. Нее.. Во временное окно можем неуложиться, давайте на си, без объектов интерфейсов и т.п.
3. Что вы ерундой занимаетесь, у нас есть уже топология разведенная под этот кодек, положим её на чип и не будем париться, а апгрейд потребуют, мы новых чипов напилим.
В общем бабло побеждает зло, за что платят то и делаем.

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

Архат, а теперь внимательно посмотри на последний (самый нижний) код в правой колонке.

Я позволю себе процитировать:

Beginer123 пишет:

void setup() {
  ledbtnSetup(13, 4, LOW);
  ledbtnSetup(12, 3, LOW);
  ledbtnSetup(11, 2, LOW);

  do{
    ledbtnRun(13,4);
    ledbtnRun(12,3);
    ledbtnRun(11,2);
  }while(1);
}

void loop(){}
/*
 * Скетч использует 990 байт (3%) памяти устройства. Всего доступно 32256 байт.
 * Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт. */
 */

Он у тебя вообще компилируется? У меня - нет.

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

----------

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

Logik
Offline
Зарегистрирован: 05.08.2014

Ворота пишет:

Ну, а так, в целом - брось это мелкое жульничество. 

Одобряю призыв!

Чего это loop пустой и в сетапе какойто цикл вечно крутится.

А ну в луп то что в нем должно быть вынести! Не жульничать!

 

alexbmd
Offline
Зарегистрирован: 15.01.2016

Ворота если знаешь ошибку не проще ли на нее указать? Зачем этот срач

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

alexbmd пишет:
Ворота если знаешь ошибку не проще ли на нее указать?
Кто я такой, чтобы указывать на ошибки Великого? Это ты любишь "дискутировать" с людьми на порядки больше тебя знающими, а я своё место адекватно оцениваю.

Тем более, что ошибок у Архата не бывает - у него "все баги - фичи". Это просто мы тупые, зашоренные недоумки не понимаем высокого полёта его мысли.

Logik
Offline
Зарегистрирован: 05.08.2014

Та какой там срач )) Он обявы ledbtnSetup и ledbtnRun незаметил. В левом скетче тоже #include "oopsample.h" не достает. То все фигня не по теме.

ПС. Даеш код цикла в LOOP!!!!

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

Logik пишет:

Он обявы ledbtnSetup и ledbtnRun незаметил. 

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

Beginer123
Offline
Зарегистрирован: 23.11.2018

Ещё раз, Я - НЕ Архат, всего лишь взял несколько уроков у него по Си. Года назад, вообще не имел понятия об Ардуино. Спасибо конечно, приятно когда тебя путают с твоим Учителем. :)

Вот полный код, аналогично проверял и Ваш:

/**
 * Кнопки с подсветкой.
 * ====================
 * 
 * Кнопка подтянута к питанию: нажата - замыкание на землю (LOW)
 * Встроенный светодиод управляется по аноду:
 * HIGH - горит, катод(-) на земле, резистор подтяжки на входе управления и аноде(+)
 */

/**
 * for SETUP()
 * настройка ножек пары "кнопка с подсветкой"
 */
void ledbtnSetup(uint8_t pLed, uint8_t pBtn, bool mode)
{
  pinMode((pBtn), INPUT_PULLUP);
  pinMode((pLed), OUTPUT);
  digitalWrite((pLed), (mode));
}
/**
 * Согласование состояния светодиода с нажатием кнопки:
 * нажата - светодиод включен, иначе - выключен
 */
void ledbtnRun(uint8_t pLed, uint8_t pBtn)
{
  digitalWrite(pLed, !digitalRead(pBtn));
}

void setup() {
  ledbtnSetup(13, 4, LOW);
  ledbtnSetup(12, 3, LOW);
  ledbtnSetup(11, 2, LOW);

  do{
    ledbtnRun(13,4);
    ledbtnRun(12,3);
    ledbtnRun(11,2);
  }while(1);
}

void loop(){}
/*
 * Скетч использует 990 байт (3%) памяти устройства. Всего доступно 32256 байт.
 * Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт.
 */

Вот скрин результата компиляции .. не знаю что Вы там не сумели, разбирайтесь сами.

Beginer123
Offline
Зарегистрирован: 23.11.2018

Пардон, это для какой-то платы Йун .. фиг знает что это. Исправил на УНО:

Beginer123
Offline
Зарегистрирован: 23.11.2018

В любм случае, разница читаемости, понимаемости как самой функции setup(). так и понимаемость добавленного кода ДЛЯ улучшения - на лицо.

Вам ещё раз спасибо.

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

Beginer123 пишет:

Я - НЕ Архат,

Завязывай, надоел.

Beginer123 пишет:

Вот полный код

Т.е. ты признаёшь, что код, который ты выкладывал раньше - самый нижний в правой колонке (вкупе со вторым снизу, разумеется), не компилируется? Да или нет?

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

Logik
Offline
Зарегистрирован: 05.08.2014

Ворота пишет:

Logik пишет:

Он обявы ledbtnSetup и ledbtnRun незаметил. 

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

Код собирается. Спецом включил нумерацию строк и коменты потер, чтоб все в одной картинке.

Похоже вопрос кто чего готовить не умеет уже решен.

Logik
Offline
Зарегистрирован: 05.08.2014

Снова обращаю внимание на жульничество Ворот! 

Основной цикл приложения пуст. 

Приведи код к нормам ардуины! Цикл перенеси в Loop! Тогда и сравнивай.

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

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

Logik пишет:

Ворота пишет:

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

Код собирается. 

Т.е. ты скопипастил коды, и они собираются? Брехать - не мешки ворочать?

Почему код в твоей картинке не соответсвует коду Архата, который я цитировал? Где дважды закрытый комментарий в конце? Неужели и с ним собирается? Или ты его "поправил". Так если исправить ошибки, то, конечно, собирается. Только это называется подлог!

Впрочем, я уже догадываюь, что дважды закрытый комментарий мне приснился. Слава Богу, он всё ещё там и любой может убедиться в твоём подлоге.

Собирается у него ...  :)))

Logik пишет:

Похоже вопрос кто чего готовить не умеет уже решен.

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

Какие уж тут вопросы, всё понятно.

 

Beginer123
Offline
Зарегистрирован: 23.11.2018

Logik? так там вот такое вот выходит и оно понятно почему, объекты-то у него локальны в сетапе ..

Зато как других лажал-то! Спасибо, не заметил бы сам.. не то обсуждалось

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

Logik пишет:

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

И что с того, что ты перенесёшь? Это будет твой код, а не мой.

Я написал так, чтобы оно не занимало лишней памяти потому, что я умею это готовить!

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

Вот собственно и всё.

Beginer123
Offline
Зарегистрирован: 23.11.2018

А если вынести в глобал, то проявится ЦЕНА "ООП улучшения кода" вот так:

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Logik пишет:

Код собирается. Спецом включил нумерацию строк и коменты потер, чтоб все в одной картинке.

Код НЕ собирается именно потому, что два раза закрыт нижний комент, который ты убрал.

Мелкое, и очень нечистоплотное передергивание. Ты, Логик, все больше превращаешься в говно, прости мой французский.

Beginer123
Offline
Зарегистрирован: 23.11.2018

ворота, огромное Вам спасибо. Сохранил тему, она достойна статьи на хабре.

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

Beginer123 пишет:

А если вынести в глобал, то проявится ЦЕНА "ООП улучшения кода" вот так:

Ещё один умелец говнокодить.

Именно об этом я писал последний абзац стартового сообщения - перечитай. "Можно ли наговнокодить? Можно - специалисты имеются!" :))))

Beginer123
Offline
Зарегистрирован: 23.11.2018

Да, я уже понял кто тут "специализд". В общем - всё ясно. Архат и в оценке форума в целом оказался прав на все 146%. Выпиливаюсь, всем не кашлять. Удачи в оболванивании новичков.

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

Beginer123 пишет:

ворота, огромное Вам спасибо. Сохранил тему, она достойна статьи на хабре.

Не за что.

Поскольку ты, как всегда, отказался признать свой очевидный пук в лужу, объяснять тебе почему нельзя менять код в сравнении я, прости, не буду. Бисер перед свиньями не мечут. Можешь быть свободным.

Beginer123
Offline
Зарегистрирован: 23.11.2018

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

Неужели такую фигню надо ещё и растолковывать? Во тупой..

Всё, за сим досвидос, не кашляй, урод. На этом форуме - меня больше не будет. Архат - прав, тут одни идиоты, не способные убрать лишний коммент из кода. А вот на Хабр попробую выложить, заодно может и примут..

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

Beginer123 пишет:

Архат - прав, тут одни идиоты,

Даже Лоджик?

Logik
Offline
Зарегистрирован: 05.08.2014

Beginer123 пишет:

А если вынести в глобал, то проявится ЦЕНА "ООП улучшения кода" вот так: .....

 

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

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

Да, Архат, недооценил я Вас. Думал, уж очевидную опечатку признаете, типа "опечатка - с кем не бывает". Но ни фига! В Вашей опечатке виноваты не Вы, а "тупой урод" - Ваш оппонент.

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

Удачи Вам! Не прощаюсь, т.к. знаю, что Вы ещё вернётесь. 

Logik
Offline
Зарегистрирован: 05.08.2014

wdrakula пишет:

Logik пишет:

Код собирается. Спецом включил нумерацию строк и коменты потер, чтоб все в одной картинке.

Код НЕ собирается именно потому, что два раза закрыт нижний комент, который ты убрал.

Мелкое, и очень нечистоплотное передергивание. Ты, Логик, все больше превращаешься в говно, прости мой французский.

Нахера мне в код копировать

/*
 * Скетч использует 990 байт (3%) памяти устройства. Всего доступно 32256 байт.
 * Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт. */
 */

Рехнулись шоле на почве ООП.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Beginer123 пишет:

...бла-бла-бла ...Неужели такую фигню надо ещё и растолковывать?

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

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

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

Logik пишет:

Нахера мне в код копировать

А нахера тогда было влазить? Я сказал, что код Архата не компилится. Ты взял его, исправил, скомпилил и покатил на меня телегу. Ты так-то здоров вообще?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Logik пишет:

Нахера мне в код копировать

/*
 * Скетч использует 990 байт (3%) памяти устройства. Всего доступно 32256 байт.
 * Глобальные переменные используют 9 байт (0%) динамической памяти, оставляя 2039 байт для локальных переменных. Максимум: 2048 байт. */
 */

Рехнулись шоле на почве ООП.

Здоров ли ты, дорогой? Ты понимаешь значение простых фраз на упрощенном русском?

Например фразы: "Выложенный код не компилируется". И отличие этой фразы от: "Выложенный код легко исправить для компиляции".

 

Schwarz78
Offline
Зарегистрирован: 19.01.2019

А по-моему это отличный пример, как не надо использовать ООП там, где он не нужен. 147 строчек лишнего кода там, где достаточно 20, говорят сами за себя.

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

Schwarz78 пишет:
говорят сами за себя
Ну, если Вам говорят и Вы это услышали - прекрасно!