реклама на сайте
подробности

 
 
13 страниц V  < 1 2 3 4 5 > »   
Reply to this topicStart new topic
> Как писать на С++ при создание приложений под ARM, Примеры
dxp
сообщение Jun 22 2011, 06:29
Сообщение #31


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 22 2011, 06:38
Сообщение #32


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(andrewlekar @ Jun 22 2011, 08:57) *
Использование шаблонов С++ сильно тормозит компиляцию

Вместо двух секунд аж все десять! biggrin.gif
Цитата
Не моголи бы Вы подсказать, по какой литературе обучались?

Ну как минимум ссылка на Александреску уже висит sm.gif


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 22 2011, 06:40
Сообщение #33


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(andrewlekar @ Jun 22 2011, 11:57) *
(наследование от интерфейса и поточная обработка), то тут же вся система станет крайне неустойчивой.
Почему? В чём причины неустойчивости?

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
Конкретно: множественное наследование сразу ставит крест на проекте,

Поясните? И причём тут множественное наследование? О нём вообще ни слова не было сказано.

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
перегрузка функций и операторов приводит к очень хитрым багам,

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

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
развесистая иерархия наследования приводит к хрупкости системы - очень высокая связность элементов...

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

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
Использование паттернов не имеет отношения к С++, но в микроконтроллерах не имеет особого смысла. Куда можно в AVR засунуть синглтон?!

Да как обычно - чтобы избавиться от зависимости порядка создания объектов при раздельной компиляции файлов проекта. Затраты на него копеечные.

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
Использование шаблонов С++ сильно тормозит компиляцию

Да, несколько секунд лишних, обычно, приходится потратить. sm.gif

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
и плохо контролируется по расходу памяти.

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

Цитата(andrewlekar @ Jun 22 2011, 11:57) *
В общем, это неправда, что С++ оправдан везде, где оправдан С.

Технически с точки зрения эффективности везде. А то, что голову надо включать, так это универсальное правило для любого ЯП. Единственное, с чем соглашусь, что С++ требует больше времени на изучение в силу много большего разнообразия и сложности самого языка. Это его единственный объективный недостаток перед С.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 22 2011, 06:53
Сообщение #34


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(andrewlekar @ Jun 22 2011, 08:57) *
В общем, это неправда, что С++ оправдан везде, где оправдан С.


Не согласен категорически, во всяком случае, C++ в программировании можно использовать и «ограничено», не зарываясь в тонкости ООП, при этом не платишь за то, что не используешь.


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
dxp
сообщение Jun 22 2011, 07:37
Сообщение #35


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(haker_fox @ Jun 22 2011, 08:05) *
Не моголи бы Вы подсказать, по какой литературе обучались? Или это опыт?

В основном по Страуструпу. Если есть реальный интерес к С++, то обязательно нужно прочитать его книжку "Дизайн и эволюция С++", она хоть и не техническая по языку, но зато из её прочтения куда лучше становятся понятны концепции языка, причинно-следственные связи, почему сделано так или иначе, а не иным способом. Очень полезное чтиво для понимания философии С++. Книжка, кстати, небольшая и читается очень легко.

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

На самом деле уровень проблем, который мы тут подняли, это в среде профессиональных программистов просто "асфальтированное шоссе", ко которому ехать легко и просто, это обычные штатные вещи, можно сказать тривиальные для них. Просто в embedded области в силу того, что С++ ещё только занимает позиции, и эти понятия, приёмы и средства языка идут в новинку. Но это и хорошо - то, что профессиональным РС программерам кажется рутиной и скукотой, для нас является прикольными фишками, которые вызывают искренний интерес и мотивируют работу. Второй момент: для нас это всё близко к железу, когда embedded программист пишет код, он всегда представляет, во что выльется реализация (если он хороший программист, конечно), поэтому чёткое понимание связи кода на С++ и его аппаратной реализации тоже пробуждает интерес. РС программисту в этом смысле хуже - от него реализация сидит слишком далеко. Кроме того, эффективное написание программ для настольных машин давно требует использования какого-нить развитого фреймворка, и программист оказывается заключённым в определённые рамки, выйти за которые он по сути не может - иначе сразу потеряет эффективность работы. Embedded программист в значительной степени свободен от этого, что предоставляет куда большие возможности для творчества. А именно творческое начало в любой работе делает эту работу интересной и желанной. Вот как-то так.

Цитата(Danis @ Jun 21 2011, 20:27) *
P.S. может в контексте этой темы и ваших постов Страуструпа выложить?

В смысле? Книжку его выложить или что?

Цитата(scifi @ Jun 21 2011, 21:37) *
Другими словами, средства полиморфизма из Си++ могут быть оправданы там, где на Си нужно было бы вводить "поле типа" или массив указателей на функции.
Неудивительно, что у меня нет к этому тяги: в моих задачах это редко встречается :-)

Ну, это ведь от целей зависит. И конечно, можно результат получать разными способами. Когда я ещё находился в процессе изучения С, был период, когда конструкции языка типа операторов if/for/while/switch уже были уверенно освоены, а концепция указателей на функции ещё не была - там один синтаксис выражения, задающего массив указателей на функции, просто пугал своей замороченностью и сложностью. И когда нужно было вызывать функции по условию, то городился switch, в котором перебором вызывался нужный код. Когда прогресс достиг и понимания концепции указателей на функции и возникла привычка к разбору кода "изнутри-наружу" в выражениях, то массивы указателей на функции стали применяться широчайшим образом для решения тех же задач, которые до этого решались исключительно с помощью операторов ветвления. Т.ч. возможно стоит пересмотреть существующие стереотипы, может это оказаться и не напрасным.

Цитата(Danis @ Jun 21 2011, 22:55) *
Маленько не так. Полиформизм дает возможность создавать множественные определения для операций и функций, что более абстрагирует программы. Конкретное определение, которое будет использоваться, зависит от задачи. В результате в крупном проекте коэффициент повторного использования кода возрастает. Си, к сожалению такой возможности не предоставляет.

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

* * *


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

Речь идёт о передаче сообщений. Есть программа, в которой в разных её местах возникают события и нужно их как-то передавать на обработку. Причём, нужно сделать так, чтобы при необходимости добавить новый тип сообщения не нужно было перелопачивать существующий код. Иными словами, нужно, чтобы та часть программы, к которой попадает сообщение, как-то сама распознавала тип объекта-сообщения и обрабатывала его, если сообщение предназначено для неё, и игнорировала в противном случае. При этом и создание типов (классов) сообщений, и их посылка, и их приём были простыми и прозрачными для пользователя. Это чем-то похоже на технологию RTTI (Run Time Type Identification), поддерживаемую С++ и реализуемую на основе dynamic_cast<>, но в RTTI является довольно "тяжёлым" механизмом и не очень катит в embedded (к слову, не все компиляторы для МК и поддерживают это).

По организации. Данный пример взят из рабочего проекта, где есть небольшой самописный GUI, но сам принцип передачи сообщений, в общем, не зависит от того, где это применяется, и может быть обобщен на другие задачи. В данном примере есть иерархия классов, где заглавный абстрактный базовый класс выглядит следующим образом:
Код
    //--------------------------------------------------------------------------
    class TObject
    {
    public:
        virtual void on_message(TBaseMsgWrapper *msg_wrp) = 0;

    };
    //--------------------------------------------------------------------------

Т.е. в нём определена одна (при желании это можно расширить) чисто виртуальная функция - приёмник сообщений. В программе от этого класса отнаследованы все классы GUI (начиная с класса TWidget) и некоторые другие классы. На любом уровне иерархии функция-приёмник сообщений on_message() может быть переопределена с целью задания поведения при приёме сообщения - ведь разные объекты могут ждать разные типы сообщений. В частности, далее там есть класс TWidget, в котором уже функция on_message() имеет вполне конкретное определение (см ниже).

Аргументом on_message() является указатель на базовый класс сообщений - все классы сообщений генерируются на основе этого класса. Далее будет понятно, зачем это сделано и как реализовано - кстати, тут тоже появляется полиморфное поведение для функции, которая возвращает идентификатор сообщения.

В общем, нужно, чтобы был простой и эффективный механизм генерации служебной информации, обозначающей тип сообщения, и эффективное средство проверки типа сообщения. В результате нам с корешем (он, кстати, тоже на элхе появляется под ником mikeT) удалось родить следующее (включение заголовочных файлов скипнуто):
Код
//------------------------------------------------------------------------------
inline uint16_t generate_id() { static uint16_t id; return ++id; }

class TBaseMsgWrapper
{
public:
    virtual uint16_t get_id() = 0;
};

template<typename T> class msg_wrapper : public TBaseMsgWrapper
{
public:
    msg_wrapper(T *msg) : body(msg), TBaseMsgWrapper() { }
    
    static  uint16_t get_class_id() { static const uint16_t id = generate_id(); return id; }
    virtual uint16_t get_id()       { return get_class_id(); }
    
    T *get_msg() const { return body; }
    
private:
    T *body;
};

template<typename T> T *check_msg(TBaseMsgWrapper *msg_wrp)
{
    if( msg_wrp->get_id() == msg_wrapper<T>::get_class_id() )
    {
        return (static_cast<msg_wrapper<T> *>(msg_wrp))->get_msg();
    }
    else
    {    
        return 0;
    }
}

template<typename T> bool send_message(T *msg, gui::TObject *dst)
{
    msg_wrapper<T> msg_wrp(msg);
    dst->on_message(&msg_wrp);
    
    return true;
}
//------------------------------------------------------------------------------

С целью достижения как можно более простой и дешёвой реализации в качестве типа идентификатора сообщения был выбран целочисленный тип (в данном случае 16-битное беззнаковое целое). Для каждого типа сообщений генерируется уникальный идентификатор - целочисленное значение. Генератором идентификаторов служит функция generate_id(), которая на каждый вызов возвращает новое значение.

Далее, сообщение технически представляет собой тело сообщения - это тип, определяемый пользователем, который может быть произвольным - классом (или встроенным типом, но понятно, что идеологически правильно использовать класс или перечислимый тип - в общем, чтобы тип был уникальным), и класс-обёртку для тела сообщения - на каждый тип сообщения генерируется своя обёртка. Генерируется она на основе шаблона с аргументом в виде типа тела сообщения - шаблон msg_wrapper<>. Как видно из кода выше, этот шаблон генерирует классы, которые все являются производными от базового класса TBaseMsgWrapper, который является абстрактным базовым классом и определяет метод get_id(), который переопределяется в производных. Цель этого - чтобы в каждом производном классе эта функция возвращала уникальный идентификатор только своего класса, т.е. только соответствующего своему типу сообщений.

Ну, и до кучи ещё определена пара шаблонных функций (шаблонные потому, что типы сообщений разные), которые отвечают за отправку сообщения и проверку его типа. Функция send_message() принимает указатель на тело сообщения (сам объект тела сообщения должен быть создан до этого - где и как, это компетенция пользователя - можно в стеке, можно в статической памяти, а можно хоть и в свободной - как удобно и приемлемо) и указатель на объект, которому сообщение отсылается, т.е. объект назначения. Внутри функции создаётся объект-обёртка сообщения, в которой есть функция, возвращающая уникальный идентификатор для данного типа сообщения, затем делается вызов метода on_message() объекта назначения с передачей ему сообщения.

На приёме остаётся только проверить, что сообщение "свое", и если это так, то обработать его, в противном случае проигнорировать.

Использование. В приборе, для которого написана программа есть несколько кнопок управления (конкретно их 4 штуки). При нажатии на любую из них генерируется соответствующее событие, по котором формируется сообщение, посылаемое текущему активному объекту (указатель TObject *focus содержит адрес активного объекта).
Код
//------------------------------------------------------------------------------
     // где-то в заголовочном файле
    enum TKeyMessage
    {
        kmNONE,
        kmSEL,
        kmPOWER,
        kmPLUS,
        kmMINUS
    };

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

        gui::TKeyMessage key_code = gui::kmNONE;
        if( dev_key_events.sel.IsClick() )   // если кнопка "Select" нажата
        {
            key_code = gui::kmSEL;
            send_message<gui::TKeyMessage>(&key_code, focus);
        }
        if( power_key_event.IsClick() )
        {
            key_code = gui::kmPOWER;    // если кнопка "Питание" нажата
            send_message<gui::TKeyMessage>(&key_code, focus);
        }
        ...
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//
//  На приёме сообщения виджетами:
//
void TWidget::on_message(TBaseMsgWrapper *msg_wrp)
{
    gui::TKeyMessage *p = check_msg<gui::TKeyMessage>(msg_wrp);

    if(p)
    {
        switch(*p)
        {
        case gui::kmSEL:    handle(); break;
        case gui::kmPOWER:  back();   break;
        case gui::kmPLUS:   next();   break;
        case gui::kmMINUS:  prev();   break;
        default: print("Error");
        }
    }  
}
//------------------------------------------------------------------------------

Тут первым делом проверяется, соответствует ли тип сообщения ожидаемому. В частности, тут мы ждём сообщение типа TKeyMessage. Если реально сообщение будет другого типа, то функция check_msg() вернёт 0, и сообщение будет проигнорировано. Проверка сводится к банальному сравнению двух целых, что выполняется очень эффективно. Если тип сообщения соответствует ожидаемому, то будет возвращён указатель на тело сообщения, которое дальше может быть использовано по назначению. В частности, тут производится вызов функций в соответствии с информацией о нажатой кнопке прибора. Функции handle(), back(), next() и prev() являются виртуальными, изначально определены в TWidget и переопределяются в виджетах-потомках - это как раз тот случай, который был описан в предыдущем посте.

Здесь все виджеты, которые не переопределили у себя функцию on_message(), будут работать в логике TWidget::on_message(). Если необходимо у какого-то объекта иметь другую логику, то достаточно этого класса определить его собственную on_message(), и обработка сообщений для именно этого объекта будет реализована по его собственной схеме.

В общем, тут можно расширять и вверх, и вширь - т.е. создать столько типов сообщений, сколько нужно, и это всё без изменения остального (уже нередко стабильного) кода без опасности что-то поломать в нём. При этом не надо заботиться о правильности обработки - пользователь только создаёт тело сообщения, делает send_message() и check_message() в точке приёма. Всё остальное делает компилятор и сгенерированный код на рантайме.

* * *

Этот же приём был портирован на фреймворк Qt. Там особенность в том, что уже есть механизм передачи событий (QEvent) и при портировании было желание использовать его. Задумка у авторов Qt в части событий такова, что там события делятся на два типа - системные (всякие события от клавиатуры, мыши и прочего) и пользовательские. И предусмотрен идентификатор событий - целое. sm.gif Разделено там так: события от 0 до 1000 - это системные события, а от 1000 до 65535 - пользовательские. Реализация:
Код
#include <QApplication>
#include <QEvent>

//------------------------------------------------------------------------------
inline int generate_id() { static int id = QEvent::User; return ++id; }
//------------------------------------------------------------------------------
template<typename T> class msg_wrapper : public QEvent
{
public:
    msg_wrapper(T msg)
        : QEvent( static_cast<QEvent::Type>( get_class_id() ) )
        , body(msg)
    {
    }
    
    static  int get_class_id() { static const int id = generate_id(); return id; }
    
    T *get_msg() { return &body; }
    
private:
    T body;
};
//------------------------------------------------------------------------------
template<typename T> T *check_msg(QEvent *msg_wrp)
{
    if( msg_wrp->type() == msg_wrapper<T>::get_class_id() )
    {
        return (static_cast<msg_wrapper<T> *>(msg_wrp))->get_msg();
    }
    else
    {    
        return 0;
    }
}
//------------------------------------------------------------------------------
template<typename T> bool send_message(QObject *dst, T msg)
{
    msg_wrapper<T> msg_wrp(msg);
    return QApplication::sendEvent(dst, &msg_wrp);
}
//------------------------------------------------------------------------------

Использование. Тело сообщения - событие переименования элемента комбобокса:
Код
class TComboBoxRenameEvent
{
public:
    TComboBoxRenameEvent(QString NewValue): Value(NewValue){ }

    QString value() const { return Value; }

private:
    QString Value;
};


Сам класс комбобокса - в нём нужно переопределить функцию-обработчик события customEvent() (виртуальная).
Код
class TComboBox : public QComboBox
{
    Q_OBJECT

public:
    explicit TComboBox(QWidget *parent = 0) : QComboBox(parent) { }

    TComboBox & operator=(const TComboBox & );

protected:
    virtual void customEvent(QEvent *Message);
};


Генерация и отсылка сообщения (по кнопке Ok в диалоге переименования генерируется сигнал, к которому подконнекчен слот, представленный ниже):
Код
void TRenameDialog::on_pbOk_clicked()
{
    TComboBoxRenameEvent msg_body(ui->leName->text());
    send_message<TComboBoxRenameEvent>(Dst, msg_body);
}


И, наконец, приём и обработка сообщения:
Код
void TComboBox::customEvent(QEvent *Message)
{
    TComboBoxRenameEvent *msg = check_msg<TComboBoxRenameEvent>(Message);
    if( msg )
    {
         ...; // обработка сообщения
    }
}
//------------------------------------------------------------------------------

В общем-то, сама по себе идеология передачи событий в Qt очень похожа на описанную выше для embedded системы, она проста и логична, будучи основанной на передаче события в виде указателя на базовый класс. Но тут есть недостаток - приходится руками генерировать идентификатор типа, руками проверять на соответствие и делать явное преобразование типов (а явное преобразование типов - это, как правило, не гуд, и как утверждает тов. Страуструп: "...обычно указывает на ошибки проектирования", поэтому всегда желательно каждый такой случай рассматривать внимательно и при малейшей возможности прятать с глаз долой; в любом случае нехорошо, когда пользовательский код пестрит явными преобразования типов). Описанный приём просто все эти действия автоматизирует и предоставляет программисту более простой и безопасный интерфейс для использования.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Jun 22 2011, 07:38
Сообщение #36


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Цитата
Поясните? И причём тут множественное наследование? О нём вообще ни слова не было сказано.

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

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

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

Цитата
Да как обычно - чтобы избавиться от зависимости порядка создания объектов при раздельной компиляции файлов проекта. Затраты на него копеечные.

Ага, сначала создавать себе проблемы, используя С++, а потом мужественно их решать sm.gif

Цитата
А то, что голову надо включать, так это универсальное правило для любого ЯП.

На С++ голову уж слишком сильно нужно включать. Язык должен ограничивать программиста в его бурных устремлениях, а чрезмерная гибкость С++ позволяет выстрелить себе в ногу и успешно завалить проект. С со статической аллокацией - вот правильный выбор программиста микроконтроллеров.
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jun 22 2011, 08:13
Сообщение #37


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



QUOTE (andrewlekar @ Jun 22 2011, 13:57) *
В общем, это неправда, что С++ оправдан везде, где оправдан С.

Похоже, что назревает очередной спор (VS).


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 22 2011, 08:28
Сообщение #38


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(andrewlekar @ Jun 22 2011, 11:38) *
А неаккуратная работа с памятью более вероятна как раз в С++, потому что там куда чаще встречается динамическое размещение объектов.


Набрался терпения и решил немного поработать писателем и корректором. Да, действительно адресная арифметика и динамическое размещение памяти при неопытности «да и опытности» тянет за собой источники потенциальных ошибок. Microsof, например, для решения этой проблемы и не только, разработал платформу .NET, под которую можно писать приложения на многих языках программирования, в частности применять C++ с расширением управляемости. (С++.Net). Код здесь, выполняется под управлением обще языковой среды выполнения CLR (Common Language Runtime), называется «управляемым кодом». Программы состоят из кода и данных, и обще языковая среда выполнения CLR обеспечивает поддержку и управляемым данным, и управляемому коду. Управляемые данные размещаются в управляемой динамически распределяемой области памяти (куче), которая имеет весьма ценную особенность — автоматическую сборку мусора (garbage collection). Если при создании программ на обычном C++ программист должен сам создавать средства управления динамически распределяемой областью памяти, то обще языковая среда выполнения CLR реализует этот процесс, отслеживая ссылки на объекты и автоматически освобождая ресурсы, занятые объектами, которые стали недоступны программе. Фактически, управляемые и неуправляемые (к которому мы все так привыкли) код и данные на C++ могут быть определены в одном и том же исходном файле, и в некоторой степени эти два мира могут взаимодействовать. Хотя использование управляемого кода и данных имеет много преимуществ (пример выход за пределы массива, на этапе run-time сразу выбросит исключение) оно может привести к снижению производительности и потере гибкости. Поэтому во многих случаях неуправляемый C++, при опытности и знаниях, оказывается лучшим выбором для создания программ.


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Jun 22 2011, 08:32
Сообщение #39


Познающий...
******

Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



По сравнению с уважаемым dxp, я вообще не программист crying.gif Но, тем не менее, позволю изложить и свою точку зрения.

QUOTE (andrewlekar @ Jun 22 2011, 16:38) *
Адресная арифметика - это также и чисто микроконтроллерная область

А к чему это уточнение? С адресами на любой платформе работать приходится.
QUOTE (andrewlekar @ Jun 22 2011, 16:38) *
А неаккуратная работа с памятью более вероятна как раз в С++, потому что там куда чаще встречается динамическое размещение объектов.

Не обязательно на Си++ размещать объекты динамически. Я не размещаю. А если размещаете, то нужно делать это корректно.
QUOTE (andrewlekar @ Jun 22 2011, 16:38) *
На С++ голову уж слишком сильно нужно включать.

Ну так это инструмент профессиональный rolleyes.gif
QUOTE (andrewlekar @ Jun 22 2011, 16:38) *
Язык должен ограничивать программиста в его бурных устремлениях, а чрезмерная гибкость С++ позволяет выстрелить себе в ногу и успешно завалить проект. С со статической аллокацией - вот правильный выбор программиста микроконтроллеров.

А почему Вы считаете, что разработчики компилятора знают лучше, что мне можно, а что - нельзя. В этих случая Pascal нужно выбирать. Он ограничивал.


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
Dima_G
сообщение Jun 22 2011, 08:35
Сообщение #40


Местный
***

Группа: Свой
Сообщений: 279
Регистрация: 2-07-08
Из: Новосибирск
Пользователь №: 38 699



Цитата(Hellper @ Jun 19 2011, 03:15) *
Такие примеры, чтобы показывали удобство и силу использование ООП, и тянуло сразу садится, вникать и кодить.


Вот мой пример удобного использования С++. У меня все структурные единицы обозваны как "Сервисы", взаимодействуют друг с другом посредством сообщений. Причем, иногда одно сообщение может доставляться нескольким сервисам одновременно (а может и ни одному - уходить в пустоту).
Основная фича - источник сообщения ничего не знает о количестве и наличии получателей. Получатели - ничего не знают о источнике. Получателей сообщения определяет тип сообщения.

Вот реальный пример использования. Системный сервис рассылает всем существующим сервисам (потомкам base_service) какие-то синхронизационные сообщения. Системный сервис ничего не знает о количестве потомков базового. Базовые - ничего о системном. Единственное, что их связывает - тип сообщения (ClSystemMessage), который один может отправить, а другой - получить


Код
base_service.h
///@class ClBaseService
///@brief Base class for services.
/// All classes, which inherited from ClBaseService will receive message from SystemService
class ClBaseService: public TClMulticastHandler<ClSystemMessage>
{
* * *
    ///@brief Called when receive message from SystemService
    ///@param clSend_ - message from SystemService
    int ProcessMulticast(ClSystemMessage& clSend_);
* * *
};



Код
system_service.h

///@class ClSystemService
///@brief System service of environment.
class ClSystemService: public TClSingleton<ClSystemService>
{
  friend class TClSingleton<ClSystemService>;
* * *
  public:
    ///@brief Send INIT signal to all services
    ///@return Count of detected errors
    int InitServices()
    {
      DebugOut("[SystemService] Init services:\n");

      // Send INIT message
      ClSystemMessage clInitMessage_(ClSystemMessage::E_INIT);
      int i32ServiceCount_ = TClMulticastEventMech<ClSystemMessage>::EmitEvent(clInitMessage_);
      
      DebugOut("**[Init %i services, %i errors]\n\n", i32ServiceCount_, clInitMessage_.u32ErrorCounter_m);
      return i32ServiceCount_;
    }
* * *
};


Прошу прощения за "портянку", почему-то не удается ни архив, ни заголовочник прикрепить
Код
#ifndef __MULTICAST_EVENT_HEADER_H__
#define __MULTICAST_EVENT_HEADER_H__

#include "sync_obj.h"
#include "singleton.h"

#include <stdint.h>

namespace ENV
{

template <class SEND_MSG>
class TClMulticastEventMech;

///@class TClMulticastHandler
///@brief Parent class for objects, which want use multicast messages
template <class SEND_MSG>
class TClMulticastHandler
{
  friend class TClMulticastEventMech<SEND_MSG>;
  protected:
    /// Protected constructor
    TClMulticastHandler();
    /// Protected virtual destructor
    virtual ~TClMulticastHandler();
    
    ///@brief Abstract method for message receiption.
    /// Will be called when someone send message with appropriate types
    /// @param clSend_ - parameter type SEND_MSG. Read only
    /// @return can't defined. Value may be used in users purposes
    virtual int ProcessMulticast(SEND_MSG& clSend_)= 0;
};


///@class TClMulticastEventMech
///@brief Pool of requestors for one-type messages
template <class SEND_MSG>
class TClMulticastEventMech:public TClSingleton<TClMulticastEventMech<SEND_MSG> >
{
  typedef       TClMulticastHandler<SEND_MSG> THandler;
  friend class  TClSingleton<TClMulticastEventMech<SEND_MSG> >;
  friend class  TClMulticastHandler<SEND_MSG>;

  public:
    ///@brief Max count of handlers for one-type message
    static const uint32_t MAX_HANDLERS = 32;
    
    ///@brief Send message to all registered requestors
    ///@param pclSend_ - pointer to const message
    static int EmitEvent(SEND_MSG& clSend_)
    {
      return TClMulticastEventMech<SEND_MSG>::Instance()->EmitEvent_nonstatic(clSend_);
    }                      
    
    ///@brief Send message to all registered requestors, except sender
    ///@param pclSend_ - pointer to const message
    ///@param pclSender_ - pointer to sender
    static int EmitEvent(SEND_MSG& clSend_, THandler* pclSender_)
    {
      return TClMulticastEventMech<SEND_MSG>::Instance()->EmitEvent_nonstatic(clSend_, pclSender_);
    }
    
    ///@brief Send message to all registered requestors, except sender
    ///@param pclSend_ - pointer to const message
    ///@param pclSender_ - pointer to sender
    static int EmitEvent(SEND_MSG& clSend_, void* pclSender_)
    {
      return TClMulticastEventMech<SEND_MSG>::Instance()->EmitEvent_nonstatic(clSend_);
    }

      
  private:
    ///Pool of requestors
    THandler* apclHandlers_m[MAX_HANDLERS];

    ///Count of registered requestors
    uint32_t      u32CountHandlers_m;
  
    ///Private constructor. Create object can only TClSingleton
    TClMulticastEventMech():u32CountHandlers_m(0){}
    
    ///Register reqiestor
    ///@param pclHandler_ - pointer to requestor object
    int Register(THandler* pclHandler_);

    ///Unregister requestor
    ///@param pclHandler_ - pointer to requestor object
    int UnRegister(THandler* pclHandler_);

    ///Hide copy constructor  
    TClMulticastEventMech(const TClMulticastEventMech&){}              
    
    ///@brief Send message to all registered requestors
    ///@param pclSend_ - pointer to const message
    ///@param pclRecv_ - pointer to message (usually use as reply)
    inline int EmitEvent_nonstatic(SEND_MSG& clSend_)
    {
      //Process all requestors
      for (uint32_t i=0; i<u32CountHandlers_m; ++i)
        apclHandlers_m[i]->ProcessMulticast(clSend_);
      return u32CountHandlers_m;
    }                  
    
    ///@brief Send message to all registered requestors, except sender
    ///@param pclSend_ - pointer to const message
    ///@param pclSender_ - pointer to sender
    inline int EmitEvent_nonstatic(SEND_MSG& clSend_, THandler* pclSender_)
    {
      //Process all requestors
      for (uint32_t i=0; i<u32CountHandlers_m; ++i)
        if (apclHandlers_m[i] != pclSender_)
          apclHandlers_m[i]->ProcessMulticast(clSend_);
          
      return u32CountHandlers_m;
    }
};


////////////////////////////////////////////////////////////////////////////////    
template <class SEND_MSG>    
  int TClMulticastEventMech<SEND_MSG>::Register(TClMulticastEventMech::THandler* pclHandler_)
  {
    TClCriticalSection<true> clCS_;

    //Check overfull requestors list
    if (u32CountHandlers_m == MAX_HANDLERS)
      Halt("TClMulticastEventMech::Register(): Count of handlers are big");

    apclHandlers_m[u32CountHandlers_m] = pclHandler_;
    return ++u32CountHandlers_m;
  }

////////////////////////////////////////////////////////////////////////////////
template <class SEND_MSG>
  int TClMulticastEventMech<SEND_MSG>::UnRegister(TClMulticastEventMech::THandler* pclHandler_)
  {
    Halt("TClMulticastEventMech::UnRegister: Unsupported!\n");
    return 0;
  }      


////////////////////////////////////////////////////////////////////////////////
template <class SEND_MSG>
  TClMulticastHandler<SEND_MSG>::TClMulticastHandler()
  {
    TClMulticastEventMech<SEND_MSG>::Instance()->Register(this);
  }
  

////////////////////////////////////////////////////////////////////////////////
template <class SEND_MSG>
  TClMulticastHandler<SEND_MSG>::~TClMulticastHandler()
  {
    TClMulticastEventMech<SEND_MSG>::Instance()->UnRegister(this);
  }


} //namespace ENV

#endif //__MULTICAST_EVENT_HEADER_H__
Go to the top of the page
 
+Quote Post
Danis
сообщение Jun 22 2011, 08:37
Сообщение #41


Twilight Zone
***

Группа: Свой
Сообщений: 454
Регистрация: 17-02-09
Из: Челябинск
Пользователь №: 44 990



Цитата(andrewlekar @ Jun 22 2011, 11:38) *
С со статической аллокацией - вот правильный выбор программиста микроконтроллеров.


С ОЗУ до 4kBytes - да, но новые МК имеют уже под сотню kBytes, как не вертись, тут увы, Вы не правы!


--------------------
Magic Friend
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Jun 22 2011, 08:44
Сообщение #42


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(andrewlekar @ Jun 22 2011, 10:38) *
Адресная арифметика - это также и чисто микроконтроллерная область. И хоть вы на чём пишите, залезать в неё придётся. А неаккуратная работа с памятью более вероятна как раз в С++, потому что там куда чаще встречается динамическое размещение объектов.


Ага, сначала создавать себе проблемы, используя С++, а потом мужественно их решать sm.gif


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



Все ваши высказывания от недостаточного знания и опыта работы с С++.

1. По поводу статической аллокации в С. И что тут такого сильно удобного? А если памяти не хватает все сразу и навсегда разместить? Не сталкивались с таким?

2. В С++ ошибки при работе с динамической памятью как раз резко сократились за счет того, что многие вещи делает компилятор автоматически (конструктор/деструктор).

3. Сам потратил много сил на перевод фирменных изделий с концепции С со статическим размещением переменных на С++ со всеми его вкусностями. Да, требуется время для продумывания концепции, реализации и отладки своих библиотек классов. Зато потом наступает полная лепота при необходимости расширения функционала устройства. Быстро и просто.

4. Насчет ненадежности работы устройств при их реализации на С++. Совершенно ничем необосновано. У нас устройства как раньше работали месяцами без перезагрузки, так и сейчас работают.
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Jun 22 2011, 09:00
Сообщение #43


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Цитата(haker_fox @ Jun 22 2011, 14:32) *
А почему Вы считаете, что разработчики компилятора знают лучше, что мне можно, а что - нельзя. В этих случая Pascal нужно выбирать. Он ограничивал.

Потому что разработчики компиляторов умные, а программист только-только Hello World освоил. sm.gif Pascal - это хорошо, но лучше Java или .NET. Вообще во всём мире С++ верно помирает, а вы наоборот в контроллеры его суете.

Цитата(sergeeff @ Jun 22 2011, 14:44) *
Все ваши высказывания от недостаточного знания и опыта работы с С++.

На С++ я успел поработать и мне не понравилось. И шаблоны, и ОО, и перегрузки - основные фичи С++ - разводят страшную грязь в коде. Да, при хорошем опыте программист научается ходить по этим граблям, но новый программист в проекте будет разбираться очень долго. sm.gif

Цитата(sergeeff @ Jun 22 2011, 14:44) *
1. По поводу статической аллокации в С. И что тут такого сильно удобного? А если памяти не хватает все сразу и навсегда разместить? Не сталкивались с таким?

2. В С++ ошибки при работе с динамической памятью как раз резко сократились за счет того, что многие вещи делает компилятор автоматически (конструктор/деструктор).

Один говорит, что статическая аллокация хороша при малом объеме ОЗУ. Другой наоборот. Да, бывает, что без динамической аллокации не обойтись - тогда приходится идти на компромисс.
Что-то я не слыхал, чтобы в С++ где-то резко сократились ошибки памяти. Наоборот, прибавилось ошибок. Утечки памяти - фирменная фича неуправляемого С++. В бусте напихали целую кучу умных указателей для борьбы с утечками и всё равно регулярно где-то подтекает на больших проектах.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Jun 22 2011, 09:32
Сообщение #44


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(andrewlekar @ Jun 22 2011, 13:00) *
И шаблоны, и ОО, и перегрузки - основные фичи С++ - разводят страшную грязь в коде.

А я так думаю наоборот - прячут с глаз долой всё лишнее и второстепенное, мешающее целостному восприятию кода.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
shreck
сообщение Jun 22 2011, 10:34
Сообщение #45


Местный
***

Группа: Свой
Сообщений: 327
Регистрация: 24-06-06
Из: Томск
Пользователь №: 18 328



Цитата(andrewlekar @ Jun 22 2011, 16:00) *
... но лучше Java или .NET...

... И шаблоны, и ОО, и перегрузки - основные фичи С++ - разводят страшную грязь в коде. Да, при хорошем опыте программист научается ходить по этим граблям, но новый программист в проекте будет разбираться очень долго. sm.gif

Так и шаблоны и перегрузки и ОО есть и в вашем любимом .NET. Получается, что в С++ эти фичи разводят грязь, а в .NET все чистенько? Это при том, что синтаксис C# очень близок к С++.
Go to the top of the page
 
+Quote Post

13 страниц V  < 1 2 3 4 5 > » 
Reply to this topicStart new topic
4 чел. читают эту тему (гостей: 4, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 00:46
Рейтинг@Mail.ru


Страница сгенерированна за 0.01603 секунд с 7
ELECTRONIX ©2004-2016