|
К знатокам, Локальные переменные. |
|
|
|
 |
Ответов
(105 - 119)
|
Sep 25 2007, 05:41
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата Почитайте что-нибудь типа "Искусства программирования" (к стыду своему забыл автора).Там на эту тему очень подробно написано. Вот че-то я не помню, что бы Кнут что-то писал про ООП. Во времена первого издания и ООП не было  Кнута, правда, читал 15 лет назад. Новое издание пробежал по диагонали (грешен), вроде особо отличий не нашел... Цитата За счет прямого использования железно-зависимых вещей ваш код работает максимально быстро и не требует дополнительных переменных. Да одна же функция ходит к железу, ну две. Не сто, не двести. У вас пара методов. Так что не аргумент. Цитата возможно на мои пристрастия и взгляды (а возможно и на взгляды Rst7) влияет то с чем мы работаем Да я не только с AVR работаю. Вот могу привести пример из другой области. Областью этой я занимаюсь исключительно как хобби, для развлечения. Есть платформа на ARM926EJS 104МГц (можно и 208). Внутри есть RTOS (Nucleos), куча всякой периферии, GUI, сокеты и прочее. Приведу пример, где заканчиваются ресурсы системы. При количестве чанков кучи больше 4500 (примерно), начинает заметно тормозить система (из-за часто используемого malloc'a и mfree). В результате простое использование какого-нибудь STL (уж ооп в полный рост. Или нет?) для разбора более-менее приличных размеров XML (или странички ОперыМини) мгновенно приводит к дикой фрагментации памяти. Приходится все делать ручками, с минимизацией фрагментации. Вот и смысл этой портабельности, если я ее применить не могу? А сам внутренний софт платформы, кстати, писан без всяких плюсов. И самое смешное, отлично был в свое время спортирован с C166 на ARM  Хотя конечно, все фунции гуев имеют первым параметром указатель на структуру (типа this), но это не плюсы. Есть и другие платформы подобного плана. И во всех плюсами и не пахнет. Кстати, одну из этих платформ портировали с AVR на ARM... До сих пор можно увидеть куски кода явно AVRовского происхождения  Ниче, пашет...
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Sep 25 2007, 08:23
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(Rst7 @ Sep 25 2007, 09:41)  При количестве чанков кучи больше 4500 (примерно), начинает заметно тормозить система (из-за часто используемого malloc'a и mfree). В результате простое использование какого-нибудь STL (уж ооп в полный рост. Или нет?) для разбора более-менее приличных размеров XML (или странички ОперыМини) мгновенно приводит к дикой фрагментации памяти. Ну так там же аллокатор настраивается. По умолчанию используется стандартный. Если у вас дикая фрагментация на нем получается, надо написать свой собственный, заточенный под конкретный размер блоков, к примеру. Он кстати получится и более быстрым  . Зато вы сможете продолжать использовать stl, и вам не придется заново писать собственные контейнеры. Цитата А сам внутренний софт платформы, кстати, писан без всяких плюсов. И самое смешное, отлично был в свое время спортирован с C166 на ARM smile.gif Хотя конечно, все фунции гуев имеют первым параметром указатель на структуру (типа this), но это не плюсы. Это тоже самый ОП (или даже ООП - если там еще какие-никакие указатели на функции появляются), только средствами С... Почему не писали на С++ - это вопрос к авторам. Может не было тогда компилятора С++ под их платформу, может еще какие резоны. Насчет "искусства программирования" - извиняюсь, имел в виду "Совершенный код" Макконнелла
|
|
|
|
|
Sep 27 2007, 09:41
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
выкладываю свой канал ... Цитата(Dog Pawlowa @ Sep 26 2007, 15:37)  Нужно иметь возможность откатить любой проект. И повторить однозначно результат компиляции любой версии. А чем не нравится система контроля версий? Если после каждого выпуска прошивки делать коммит всего, создавать таг и включать его название\номер в прошивку, то можно совершенно однозначно повторить результат... Некоторые товарищи рекомендуют включать в систему контроля версий и используемые инструменты - компилятор и т.д.
Сообщение отредактировал Непомнящий Евгений - Sep 27 2007, 09:43
Прикрепленные файлы
temp.ZIP ( 4.16 килобайт )
Кол-во скачиваний: 45
|
|
|
|
|
Sep 27 2007, 18:40
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(dxp @ Sep 24 2007, 07:38)  Нет, хак - это рассовывание переменных уровня С в РОН процессора с использованием нестандартных, непереносимых средств компилятора, имеющее последствиями как минимум ухудшение качества оптимизации со стоторы компилятора - за этим кодом нужно постоянно следить, дает ли он дейтсвительно выигрыш, и как меняется ситуация при изменении кода - не пришла ли, скажем, пора освободить пару регистров уже для компилятора, а то он что-то медленный код стал генерить - регистров ему не хватат. Т.е. хак в данном случае - это ручная низкоуровенвая оптимизация распределения ресурсов, оптимизация на уровне асма в программе на С. хорошо, допустим я соглашусь с Вами что все это был просто хак, тогда давайте сравнивим с Вашим такой код: Код volatile BYTE ADCL_; volatile BYTE ADCH_; volatile BYTE ADMUX_; volatile BYTE ADCSRA_; volatile BYTE SYSTICKSTART_; volatile BYTE PINB_; volatile BYTE PINC_; volatile BYTE PIND_;
//------------------------------------------------------------------- // Прерывание системного таймера //-------------------------------------------------------------------
void TIMER2_COMP_vect(void) __attribute__((signal)); void TIMER2_COMP_vect() { ADCL_ = ADCL; // читаем результат последнего преобразования ADCH_ = ADCH; ADMUX = ADMUX_; // новый канал ADCSRA = ADCSRA_; // запускаем новое преобразование // информируем о начале нового цикла SYSTICKSTART_= ADCSRA_; // записью значения ADCSRA в SYSTICKSTART_ // сбрасывается в 0 в основном цикле PINB_ = PINB; // читаем порты PINC_ = PINC; PIND_ = PIND; } Это уже чистый C ??? Как насчет реализации на С++ ?
|
|
|
|
|
Sep 27 2007, 19:56
|
Участник

Группа: Validating
Сообщений: 56
Регистрация: 15-10-06
Пользователь №: 21 335

|
Цитата(Dog Pawlowa @ Sep 27 2007, 18:10)  Да нравится, использую. Речь идет об общих исходниках. Допустим, я поменял общие исходники (например программный UART AVR) сегодня, 27 сентября. Но один проект будет производиться без изменений еще год, а второй требует доработки у заказчика. То есть общий исходник должен быть включен в индивидуальный проект, и он перестает быть общим. Хм ... ну таки кто мешает ветку в СКВ сделать ? Но собственно грабли возможны в другом - если поменялся компилятор - возможны варианты  IMHO в СКВ к проекту надо добавлять файлик с описанием используемых средств ....
|
|
|
|
|
Sep 28 2007, 04:31
|

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

|
Цитата(singlskv @ Sep 28 2007, 01:40)  хорошо, допустим я соглашусь с Вами что все это был просто хак, тогда давайте сравнивим с Вашим такой код: Это уже чистый C ??? Да, это уже почти чистый С - с небольшими необходимыми расширениями, без которых не обойтись. Цитата(singlskv @ Sep 28 2007, 01:40)  Как насчет реализации на С++ ? Ну, собсно, тут на плюсах особенно не развернуться, чтобы показаться во всей красе  , но и этот фрагмент я бы написал не так. Плюсатый вариант: Код #include <iom16.h>
#define INLINE _Pragma("inline=forced")
typedef unsigned char byte;
//--------------------------------------------------------- class TADC { public: INLINE void handle() { adcl = ADCL; // читаем результат последнего преобразования adch = ADCH; ADMUX = admux; // новый канал ADCSRA = adcsra; // запускаем новое преобразование systickstart= adcsra; }
private: byte adcl; byte adch; byte admux; byte adcsra; byte systickstart; } adc; //--------------------------------------------------------- class TPorts { public: INLINE void read() { pinb = PINB; // читаем порты pinc = PINC; pind = PIND; }
private: byte pinb; byte pinc; byte pind; } ports;
//------------------------------------------------------------------- // Прерывание системного таймера //------------------------------------------------------------------- #pragma vector=TIMER2_COMP_vect __interrupt void Comp_ISR() { adc.handle(); ports.read(); } Комментарий. Собственно, объекта Системного Таймера тут по сути нет. От него есть только прерывание, но собственного представления нет, поэтому я не стал его выделять в класс. Конечно, можно было бы включить в него объекты adc и ports, но мне тут не понятна их связь. Возможно, она есть и вы ее знаете - скажем оба этих объекта функционально по замыслу являются неотъемлемой частью системного таймера. Но из самого предложенного фрамента мне так не показалось. Поэтому я не стал заводить лишнуюю сущность. Вообще, это уже вопросы проектирования, область близкая, но все же не та, которую мы тут сейчас рассматриваем. В целом код на мой взгляд даже в этом мелком случае выглядит стройнее и понятнее - он подчеркивает наличие разнокачественных объектов - АЦП и портов, акцентирует внимание на функциональность кода: сначала - в обработчике прерывания - подчеркнуто, что делается, потом - как это реализуется. Такое разделение улучшает читабельность и понимбельность кода, особенно другими людьми. На С в принципе можно было бы похоже написать, если задействовать inline функции, которые появились в С99. Но С++ прямо тяготеет к такому стилю. А главное, мы тут не показываем представление и к потрохам наших объектов никто просто так не доберется. Классы, конечно, не полные, в них нет функций, которые делали бы что-то полезное с теми же значениями, считанными в обработчике прерываний. Но это просто выходит за рамки данного примера. Там тоже никаких проблем ни в реализации, ни в эффективности нет. Возможно, вы хотели как раз посмотреть реализацию прерывания внутри объекта класса. Отвечу: никакой принципиальной разницы нет - просто сама функция-обработчик прерывания была при этом объявлена внутри класса и снабжена при этом квалификатором static, только и всего. Качество кодогенерации от этого никак не зависит. Кстати, о кодогенерации. Вот, что получилось: Код In segment CODE, align 2, keep-with-next __interrupt void Comp_ISR() ??Comp_ISR: { 93FA ST -Y, R31 93EA ST -Y, R30 930A ST -Y, R16 adc.handle(); .... LDI R30, LOW(`adc`) .... LDI R31, (`adc`) >> 8 B104 IN R16, 0x04 8300 ST Z, R16 B105 IN R16, 0x05 8301 STD Z+1, R16 8102 LDD R16, Z+2 B907 OUT 0x07, R16 8103 LDD R16, Z+3 B906 OUT 0x06, R16 8103 LDD R16, Z+3 8304 STD Z+4, R16 ports.read(); B306 IN R16, 0x16 8305 STD Z+5, R16 B303 IN R16, 0x13 8306 STD Z+6, R16 B300 IN R16, 0x10 8307 STD Z+7, R16 } 9109 LD R16, Y+ 91E9 LD R30, Y+ 91F9 LD R31, Y+ 9518 RETI In segment INTVEC, offset 0xc, root `??Comp_ISR??INTVEC 12`: ........ JMP ??Comp_ISR По-моему, тут и руками лучше не напишешь.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Sep 28 2007, 04:53
|
Бывалый
    
Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615

|
Цитата(dxp @ Sep 28 2007, 08:31)  По-моему, тут и руками лучше не напишешь.  Согласен. Но добавлю. Конструкторы позволяют всю инициализацию убрать в классы. При этом получается следующие плюсы C++: -отсутствие бесчисленной инициализации в main; -в классах все видно (в одном флаконе): инициализация, реализация, все несущественное не торчит.
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|