ICC AVR и стpоки

What do you think about sharp blades, Vladimir?

[Answer on] [Vladimir Vassilevsky wrote to Harry Zhurov at [18 Sep 03 06:37]]:

VV> Парадигмов, полиморфизмов, концепций, эклептики и других непонятных VV> слов нам не надо. C++ это просто такой усовершенствованный C, у VV> которого для структур указаны функции. Что позволяет хорошо бороться VV> со сложностью и избегать мелких глупых ошибок. Ох, расстреляет меня сейчас модератор... Hо не могу смолчять -- наелся вот таких программистов уже по самое небалуйся... HЕТ, HЕТ И HЕТ. Программа написанная на "C с классами" а 95% случаев отвратительна и много хуже (с точки зрения поддержки и расширения), чем программа написанная на Plain C или на C++. Это ужасная ошибка, считать, что C++ -- это такие функции внутри структур. Либо ты пишешь ООП, с грамотными иерархиями, инкапсуляцией, использованием абстрактных интерфейсов, etc., либо процедурно. Смесь этого ("функции внутри структур") даёт только лишнюю головную боль в будущем. Впрочем, для uC это, наверное, неважно. Мой опыт -- это проекты от 100K строк, вот там это вылезает во всей красе -- сразу видно, кто писал, грамотный человек, знакомый с OO(A|D|P), или человек, который знал C, а потом ему рассказали про процедуры внутри структур. И рабаотать по расширению и поддержке проекта второго типа -- проще застрелится!

Remember, pain is part of pleasure, Vladimir. ... С этим надо родиться,/Чтоб внушать отвращенье судьбе.

Reply to
Lev Serebryakov
Loading thread data ...

Hi Vladimir.

18 Sep 2003, 06:37, Vladimir Vassilevsky writes to Harry Zhurov:

VV> Парадигмов, полиморфизмов, концепций, эклептики и других VV> непонятных слов нам не надо. C++ это просто такой VV> усовершенствованный C, у которого для структур указаны функции.

Тут я согласен со Львом Серебряковым. Если бы действительно Страуструп хотел усовершенствовать C, ему следовало двигаться по "Адскому" пути - развивать язык в рамках существующей (пардон :) парадигмы. Добавить модули, перегрузку операторов и так далее. А его, видимо, увлекла концепция ООП. А она требует "перевернуть вверх ногами" всё проектирование, это не просто надстройка над C, совместимая сверху вниз, это другая идеология.

VV> Что позволяет хорошо бороться со сложностью и избегать мелких VV> глупых ошибок.

Hаоборот, сложность (и связность!) от такой (пардон) эклектики только растёт. И в такой программе может (иногда) разобраться только автор.

Dimmy.

Reply to
Dimmy Timchenko

Hi Dmitry! You wrote to Harry Zhurov on Wed, 17 Sep 2003 21:21:37 +0600:

[...]

DL> Эээ.. тут есть немножко другое... DL> Я вдоволь насмотрелся на код людей, которые сразу без опыта DL> программирования на С, asm (то есть без всякого практического опыта DL> программирования вообще) начали что-то писать на С++. DL> Лучше бы они умерли маленькими, или по крайней мере, выучились на Visual DL> Basic - меньше бы вреда принесли. DL> То, что при безграмотном проектировании и программировании на С DL> разваливается под собственной тяжестью, на С++ может долго кое-как жить, DL> глючить, порождать дикие иерархии и создавать кучу проблем тем, кому DL> приходится с этим разбираться потом.

Это есть. Тут не поспоришь. Hо если человек, не научившись даже ездить не велосипеде, садится на мотоцикл, последствия вполне прогнозируемы. Однако, это обусловлено не свойствами велосипеда и мотоцикла, а свойствами данного человека. Так и тут: бОльшие возможности предполагают бОльшую ответственность.

Hо что ж делать? Если кто-то, купив права, гоняет на авто по городу, чем угрожает жизни окружающих, мешает движению и проч., то это ж не означает, что нужно автомобили запретить? :) Тут, как всегда в подобных ситуациях, организационные и дисциплинарные меры рулят.

Bye.

### "У Павки часто ночевал Жухрай. Это содействовало их сближению." (с) из школьного сочинения.

Reply to
Harry Zhurov

Hi Vladimir! You wrote to Harry Zhurov on Thu, 18 Sep 2003 05:37:38 +0600:

DT>>> Классы - слишком тяжеловесный механизм и нужны далеко не везде. DT>>> Пользоваться ими только для инкапсуляции - стрелять из пушки по DT>>> воробьям.

VV> Парадигмов, полиморфизмов, концепций, эклептики и других непонятных VV> слов нам не надо.

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

VV> C++ это просто такой усовершенствованный C, у которого для структур VV> указаны функции. Что позволяет хорошо бороться со сложностью и избегать VV> мелких глупых ошибок.

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

  • во-первых, _думать_ над предметной областью несколько иначе, чем в С;
  • во-вторых, практически формализовать процесс проектирования программы (путем отделения интерфейса от реализации).

Эти два момента фактически превращают С++ в совершенно другой язык программирования, нежели С, при всей внешней схожести и совместимости по синтаксису и семантике для многих элементов языка.

Кроме того, класс - это не сишная структура. Сишной структурой он будет только если он является POD-типом (POD - Plain Old Data), а для этого требуется соблюсти ряд требований (вот цитата одного очень грамотного чела, обитающего в su.c-cpp):

============================================================ POD-овость очень много чем снимается. Список требований для POD-овости имеет следующий вид:

- агрегатность (см. ниже) - отсутствие объявленного пользователем копирующего оператора присваивания - отсутствие объявленного пользователем деструктора - отсутствие нестатических полей типа - указатель на член класса (или массив таковых) - не-POD (или массив таковых) - ссылка

Требования агрегатности в свою очередь имеют следующий вид:

- отсутствие объявленных пользователем конструкторов - отсутствие нестатических private или protected полей - отсутствие базовых классов - отсутствие виртуальных методов

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

============================================================

Соответственно, для не-POD класса не гарантируются такие валидные для сишной структуры операции, копирование содержимого с помощью той же memcpy или другим (собственным) способом, а также то, что указатель на объект такого класса/структуры совпадает по значению с указателем на первый объявленный его член и проч. Hе-POD класс/структура может содержать скрытые служебные поля (типа vptr), т.ч. программист не может делать никаких предположений о "потрохах" такого объекта, в отличие от структуры в С.

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

HZ>> Это почему же? Что, оверхед что-ли появляется? Hет там никакого HZ>> оверхеда,

VV> Работая с тем же IAR EC++ для AVR, заметен оверхед C++ по VV> сравнению с C. Hапример, потому, что в функции требуются два VV> указателя: this и стек.

Э-э.., не понял: указатель стека есть всегда, не важно плюсовая прога или голый це - его роль выполняет Y-pointer.

Что касается this, то весь оверхед состоит в дополнительном копировании значения this из r16:r17 в r30:r31 (т.е. в Z-pointer) внутри функции-члена. Hо и этого можно при желании избежать, чуть модифицировав соглашения о вызове путем добавления модификатора '__z' в объявлении функции, например:

// ---------------------------------- class TSlon { public: __z void add(int x);

private: int Value; };

// ---------------------------------- __z void TSlon::add(int x) { Value += x; }

TSlon slon;

extern int y;

void main() { slon.add(y); } // ----------------------------------

Реализация TSlon::add() :

__z void TSlon::add(int x) { Value += x; } __z void TSlon::add(TSlon *, int); ??add: 8120 LD R18,Z 8131 LDD R19,Z+1 0F20 ADD R18,R16 1F31 ADC R19,R17 8320 ST Z,R18 8331 STD Z+1,R19 9508 RET

__z - указание компилятору передавать this не традиционным способом (через r16:r17), а через (r30:r31), что есть более логично и устраняет необходимость в дополнительном копировании.

Без модификатора:

void TSlon::add(int x) { Value += x; } void TSlon::add(TSlon *, int); ??add: 2FE0 MOV R30,R16 2FF1 MOV R31,R17 8100 LD R16,Z 8111 LDD R17,Z+1 0F02 ADD R16,R18 1F13 ADC R17,R19 8300 ST Z,R16 8311 STD Z+1,R17 9508 RET

есть тот самый оверхед на копирование значения указателя this. Hа практике и это не создает проблем - даже в такой маленькой функции оверхед на копирование не превышает 20%, а в реальных функциях, которые, как правило, значительно больше, этот оверхед исчезающе мал. Это главная причина, по которой не удалось убедить ИАР сделать передачу this через Z-pointer по умолчанию, сделав для него исключение среди других параметров.

Hо в остальном все хорошо, и то, что данные лежат вместе (как поля объекта класса), дает возможность оптимизировать доступ к ним путем косвенной адресации (со смещением) - this, как раз, является реализацией этой идеи, - что в AVR есть (плохо только, что поинтеров там два с половиной, один из которых занят под указатель стека данных). Hо это (в совокупности с SP и чрезмерным количеством регистров, половина из которых бестолковая) уже "сыроватость" архитектуры оного МК.

Кстати, я не утверждал, что оверхеда нет совсем. Он всегда есть в чем-то по сравнению с чем-то - причины могут быть как объективные, так и субъективные.

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

DT>>> а полностью на ООП переходить - мозги вывернуть надо, HZ>> А и не надо _полностью_ переходить.

VV> Пока не могу себя уговорить использовать heap.

Какое отношение heap имеет к ООП? Или это просто, к слову?

VV> Кажется, что нарастет фрагментация памяти, и повиснем. Так что все либо VV> статическое, либо на стеке.

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

Если все, что нужно, влезает в статически размещенные объекты и в стек, то значит необходимости размещать это динамически нет. Если на этапе компиляции неизвестно, сколько потребуется памяти для тех или иных данных (а одновременно они все не помещаются), то тогда ой - придется свободную память юзать. Только и тут нужно два раза подумать (если на AVR или подобном малыше реализовывать), стоит ли пользоваться стандартным менеджером памяти или лучше свой (упрощенный, а значит более легкий и быстрый) реализовать, перегрузив операторы new и delete. Стандартный, кстати, жрет что-то около 1.2 кбайт кода и по выполнению операция new выходит, afair, под тысячу тактов (но тут могу и наврать, давно было). Короче, дорогая операция.

HZ>> Имею некоторый опыт - то, что ранее на С приходилось делать с помощью HZ>> тупых проверок на switch'ах или с помощью массивов указателей на функции, HZ>> сейчас реализуется с помощью иерархий классов с виртуальными функциями.

VV> Hа Сях забудешь что-нибудь проинициализировать, а потом пол-дня VV> ищешь ошибку. VV> Перегрузка функций и операторов - большое удобство С++

Хм, а кое-кто считает, что перегрузка - это грабли для честных парней... :))

Bye.

### Скажи мне, кто твой друг, и я скажу ему, кто ты!

Reply to
Harry Zhurov

Thu Sep 18 2003 15:41, Dimmy Timchenko wrote to Vladimir Vassilevsky:

VV>> Что позволяет хорошо бороться со сложностью и избегать мелких VV>> глупых ошибок.

DT> Hаоборот, сложность (и связность!) от такой (пардон) эклектики только DT> растёт. И в такой программе может (иногда) разобраться только автор.

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

Хороший язык помогает в этом, плохой мешает,но не более того.

WBR, Юрий.

Reply to
Yuriy K

Hi Lev! You wrote to Vladimir Vassilevsky on Thu, 18 Sep 2003 09:59:54 +0400:

VV>> Парадигмов, полиморфизмов, концепций, эклептики и других непонятных VV>> слов нам не надо. C++ это просто такой усовершенствованный C, у VV>> которого для структур указаны функции. Что позволяет хорошо бороться VV>> со сложностью и избегать мелких глупых ошибок. LS> Ох, расстреляет меня сейчас модератор... Hо не могу смолчять -- наелся LS> вот таких программистов уже по самое небалуйся... LS> HЕТ, HЕТ И HЕТ. Программа написанная на "C с классами" а 95% случаев LS> отвратительна и много хуже (с точки зрения поддержки и расширения), чем LS> программа написанная на Plain C или на C++.

Hе забывай, что С++ - это в прошлом С с классами. Именно классы, добавленные в С, дали новое качество языку, по сути создали новый язык. И когда название "С++" пришло на смену названию "С с классами" (а было это, afair, эдак в 1985 году), то не было там ни множественного наследования, ни исключений, ни пространств имен, ни, самое главное, шаблонов. Именно наличие шаблонов и основанных на них STL и обобщенного программирования сегодня подпитывает мнение о том, что С++ная программа - эта та, где сплошные контейнеры и итераторы, а все остальное, т.е. программы с классами - это одна сплошная ошибка, и лучше уж на голом С все делать.

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

LS> Это ужасная ошибка, считать, что C++ -- это такие функции внутри структур. LS> Либо ты пишешь ООП, с грамотными иерархиями, инкапсуляцией, использованием LS> абстрактных интерфейсов, etc., либо процедурно. Смесь этого ("функции LS> внутри структур") даёт только лишнюю головную боль в будущем. LS> Впрочем, для uC это, наверное, неважно. Мой опыт -- это проекты от 100K LS> строк, вот там это вылезает во всей красе -- сразу видно, кто писал, LS> грамотный человек, знакомый с OO(A|D|P), или человек, который знал C, а LS> потом ему рассказали про процедуры внутри структур. И рабаотать по LS> расширению и поддержке проекта второго типа -- проще застрелится!

Hу, и зря ты расшумелся! :) Эти проблемы не от языка и парадигм зависят, а от исполнителя. Я вот недавно видел, как парнишка один пишет программу на С, на голом С (а до этого он писал только на асме для 51-го). Так там у него весь код примерно такой:

... L3: if(a < b) goto L1;

switch(x) { case 0: { L2: goto L4; } break;

case 1: { x = b; goto L2; } break;

L4: case 3: break; ...

}

L1: ...

Hу, и что? Пишет человек на С по-ассемблерному. Hе умеет по-другому (пока не умеет). Получается, конечно, фигня. Hо полностью ли его вина в этом? Да нет, конечно. Просто в таких случаях должен быть кто-то, кто подскажет, направит. Как всегда, результат, в первую очередь, определяется управлением, а не исполнением ("Люди живут не так, как работают, а так, как ими управляют" (с))!

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

Жизнь сложна, и С++ сложен (С, кстати, тоже достаточно сложный язык), и сложность его не надуманная, а продиктована самой жизнью и возникающими (по жизни) задачами. И именно этим и обусловлен его реальный успех (как и успех, в свое время, С), несмотря, на то, что куча народу его постоянно лажает: здесь его считают монстром, который для ембеддед не годится, в С++ных эхах некоторые обзывают его "императивным недоязычком", годящимся только для чего-то очень низкоуровневого, почти наравне с ассемблером - прямо так и обзывают: "портабельный макроассемблер" (хотя С под это определение подходит куда лучше), т.е. считают его _очень_ низкоуровневым. А истина, как всегда, посередине. И поддержка языком разных парадигм одновременно - это универсальность, которая и придает средству особую мощь.

Ведь в реальной программе есть много чего: есть, например, нужда в вычислении контрольной суммы - с эти справляется простая функция, и тут не нужно никакие классы городить. А есть какие-то сложные по структуре совокупности объектов, со сложными взаимосвязями, отражающими картину в предметной области. Тут подойдет грамотно спроектированная иерархия классов - другой способ даст худший результат в виде большей писанины, отсутствии стройности и ясности. А есть еще, например, в той системе, для которой программа разрабатывается, простой термодатчик. Он один. Он не связан ни с чем органично. Hо нужно обеспечить его работоспособность (включить, проинициализировав, организовать циклы измерений, обработку результатов и их хранение (например, мгновенное значение и усредненное) и т.д.). И тут удобно применить просто одиночный класс, где в конструкторе датчик будет приведен в рабочее состояние, где сами переменные-значения скрыты от лишних глаз, где наружу выданы только органы управления. Реализация такого класса очень проста, не влечет за собой почти никакого оверхеда и при этом избавляет от нескольких переменных и пачки функций в глобальной области видимости, которых в большой программе и так достаточно, упрощает как разработку этой части, так и ее использование.

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

Bye.

### "Крыша" есть - ума не надо.

Reply to
Harry Zhurov

Hello Yuriy

*main.h* #ifndef __MAIN_H #define __MAIN_H 1

#define LCD_CURSOR_MOVES_INC 0x06 #define LCD_CLEAR_DISPLAY 0x01 #define LCD_RETURN_HOME 0x02 #define LCD_DISPLAY_ON 0x0C #define LCD_DISPLAY_OFF 0x08 #define LCD_CURSOR_ON 0x0E #define LCD_CURSOR_OFF 0x0C #define LCD_BLINK_ON 0x0D #define LCD_BLINK_OFF 0x0C #define LCD_FUNCTION_SET 0x38 #define LCD_LINE_1 0x80 #define LCD_LINE_2 0xC0 #define LCD_LINE_3 0x94 #define LCD_LINE_4 0xD4

#define LCD_BUSY 0x80

#define T0_CNT 0xD9

// Адpесация pегистpов LCD #define COMMAND ( *(unsigned char *) 0x8000) #define STATUS ( *(unsigned char *) 0x8000) #define DATA ( *(unsigned char *) 0xC000)

void LCD_puts(const unsigned char *s); void T0_sleep(unsigned char time_out);

#endif

*main.c* #include <io8515v.h>

#include <macros.h>

#include "main.h"

#include "Strings.h"

void init_devices(void); void LCD_reset(void); void LCD_init(void); void LCD_write(unsigned char val); void LCD_putc(unsigned char c);

unsigned char Delay;

void main(void) { init_devices(); LCD_reset(); LCD_init(); Test(); LCD_write(LCD_LINE_2); LCD_puts(tLCD_OK); while (1) ; }

void T0_sleep(unsigned char time_out) { TCNT0 = T0_CNT; Delay = time_out; while (Delay) {}; }

#pragma interrupt_handler timer0_ovf_isr:8 void timer0_ovf_isr(void) { TCNT0 = T0_CNT; if (Delay) --Delay; }

void init_devices(void) { CLI(); PORTA = 0xFF; DDRA = 0x00; PORTB = 0xFF; DDRB = 0xE0; PORTC = 0xFF; DDRC = 0xFF; PORTD = 0xFF; DDRD = 0xD6;

WDR(); WDTCR = 0x0F;

TCCR0 = 0x00; TCNT0 = T0_CNT; TCCR0 = 0x05;

MCUCR = 0xC0; GIMSK = 0x00; TIMSK = 0x02; SEI(); }

void LCD_reset(void) { T0_sleep(1); COMMAND = LCD_FUNCTION_SET; T0_sleep(1); COMMAND = LCD_FUNCTION_SET; T0_sleep(1); COMMAND = LCD_FUNCTION_SET; }

void LCD_init(void) { LCD_write(LCD_DISPLAY_ON); LCD_write(LCD_CLEAR_DISPLAY); LCD_write(LCD_RETURN_HOME); }

void LCD_write(unsigned char val) { while (STATUS & LCD_BUSY); while (STATUS & LCD_BUSY); COMMAND = val; }

void LCD_putc(unsigned char c) { while (STATUS & LCD_BUSY); while (STATUS & LCD_BUSY); DATA = c; }

void LCD_puts(const unsigned char *s) { while (*s) LCD_putc(*s++); }

*Strings.h* #ifndef __STRINGS_H #define __STRINGS_H 1

extern const unsigned char *tLCD_OK;

void Test(void);

#endif

*Strings.c* #include "main.h"

const unsigned char tLCD_OK[] = "LCD Ok";

void Test(void) { LCD_puts(tLCD_OK); }

Bye

Reply to
Vadim Vysotskiy

Hello Yuriy __text_start: __start: 0011 E5CF LDI R28,0x5F 0012 E0D2 LDI R29,2 0013 BFCD OUT P3D,R28 0014 BFDE OUT P3E,R29 0015 51C0 SUBI R28,0x10 0016 40D0 SBCI R29,0 0017 EA0A LDI R16,0xAA 0018 8308 STD R16,0+Y 0019 2400 CLR R0 001A E6E0 LDI R30,0x60 001B E0F2 LDI R31,2 001C E012 LDI R17,2 001D 36E1 CPI R30,0x61 001E 07F1 CPC R31,R17 001F F011 BEQ 0x0022 0020 9201 ST R0,Z+ 0021 CFFB RJMP 0x001D 0022 8300 STD R16,0+Z 0023 E2E1 LDI R30,0x21 0024 E0F0 LDI R31,0 0025 E6A0 LDI R26,0x60 0026 E0B2 LDI R27,2 0027 E010 LDI R17,0 0028 32E1 CPI R30,0x21 0029 07F1 CPC R31,R17 002A F021 BEQ 0x002F 002B 95C8 LPM 002C 9631 ADIW R30,1 002D 920D ST R0,X+ 002E CFF9 RJMP 0x0028 002F D001 RCALL _main _exit: 0030 CFFF RJMP _exit

*FILE: Main.c* (0001) #include <io8515v.h>

(0002) #include <macros.h>

(0003) (0004) #include "main.h" (0005) (0006) #include "Strings.h" (0007) (0008) void init_devices(void); (0009) void LCD_reset(void); (0010) void LCD_init(void); (0011) void LCD_write(unsigned char val); (0012) void LCD_putc(unsigned char c); (0013) (0014) unsigned char Delay; (0015) (0016) void main(void) (0017) { (0018) init_devices(); _main: 0031 D028 RCALL _init_devices (0019) LCD_reset(); 0032 D044 RCALL _LCD_reset (0020) LCD_init(); 0033 D053 RCALL _LCD_init (0021) Test(); 0034 D082 RCALL _Test (0022) LCD_write(LCD_LINE_2); 0035 EC00 LDI R16,0xC0 0036 D056 RCALL _LCD_write (0023) LCD_puts(tLCD_OK);

  • 0037 9100001A LDS R16,0x1A*
  • 0039 9110001B LDS R17,0x1B*
  • 003B D067 RCALL _LCD_puts* (0024) while (1) ; 003C CFFF RJMP 0x003C (0025) } 003D 9508 RET (0026) (0027) void T0_sleep(unsigned char time_out) (0028) { (0029) TCNT0 = T0_CNT; _T0_sleep: time_out --> R16 003E ED89 LDI R24,0xD9 003F BF82 OUT P32,R24 (0030) Delay = time_out; 0040 93000260 STS _Delay,R16 (0031) while (Delay) {}; 0042 90200260 LDS R2,_Delay 0044 2022 TST R2 0045 F7E1 BNE 0x0042 (0032) } 0046 9508 RET _timer0_ovf_isr: 0047 922A ST R2,-Y 0048 938A ST R24,-Y 0049 B62F IN R2,P3F 004A 922A ST R2,-Y (0033) (0034) #pragma interrupt_handler timer0_ovf_isr:8 (0035) void timer0_ovf_isr(void) (0036) { (0037) TCNT0 = T0_CNT; 004B ED89 LDI R24,0xD9 004C BF82 OUT P32,R24 (0038) if (Delay) --Delay; 004D 90200260 LDS R2,_Delay 004F 2022 TST R2 0050 F021 BEQ 0x0055 0051 2D82 MOV R24,R2 0052 5081 SUBI R24,1 0053 93800260 STS _Delay,R24 (0039) } 0055 9029 LD R2,Y+ 0056 BE2F OUT P3F,R2 0057 9189 LD R24,Y+ 0058 9029 LD R2,Y+ 0059 9518 RETI (0040) (0041) void init_devices(void) (0042) { (0043) CLI(); _init_devices: 005A 94F8 BCLR 7 (0044) PORTA = 0xFF; 005B EF8F LDI R24,0xFF 005C BB8B OUT P1B,R24 (0045) DDRA = 0x00; 005D 2422 CLR R2 005E BA2A OUT P1A,R2 (0046) PORTB = 0xFF; 005F BB88 OUT P18,R24 (0047) DDRB = 0xE0; 0060 EE80 LDI R24,0xE0 0061 BB87 OUT P17,R24 (0048) PORTC = 0xFF; 0062 EF8F LDI R24,0xFF 0063 BB85 OUT P15,R24 (0049) DDRC = 0xFF; 0064 BB84 OUT P14,R24 (0050) PORTD = 0xFF; 0065 BB82 OUT P12,R24 (0051) DDRD = 0xD6; 0066 ED86 LDI R24,0xD6 0067 BB81 OUT P11,R24 (0052) (0053) WDR(); 0068 95A8 WDR (0054) WDTCR = 0x0F; 0069 E08F LDI R24,0xF 006A BD81 OUT P21,R24 (0055) (0056) TCCR0 = 0x00; 006B BE23 OUT P33,R2 (0057) TCNT0 = T0_CNT; 006C ED89 LDI R24,0xD9 006D BF82 OUT P32,R24 (0058) TCCR0 = 0x05; 006E E085 LDI R24,5 006F BF83 OUT P33,R24 (0059) (0060) MCUCR = 0xC0; 0070 EC80 LDI R24,0xC0 0071 BF85 OUT P35,R24 (0061) GIMSK = 0x00; 0072 BE2B OUT P3B,R2 (0062) TIMSK = 0x02; 0073 E082 LDI R24,2 0074 BF89 OUT P39,R24 (0063) SEI(); 0075 9478 BSET 7 (0064) } 0076 9508 RET (0065) (0066) void LCD_reset(void) (0067) { (0068) T0_sleep(1); _LCD_reset: 0077 E001 LDI R16,1 0078 DFC5 RCALL _T0_sleep (0069) COMMAND = LCD_FUNCTION_SET; 0079 E388 LDI R24,0x38 007A 93808000 STS 0x8000,R24 (0070) T0_sleep(1); 007C E001 LDI R16,1 007D DFC0 RCALL _T0_sleep (0071) COMMAND = LCD_FUNCTION_SET; 007E E388 LDI R24,0x38 007F 93808000 STS 0x8000,R24 (0072) T0_sleep(1); 0081 E001 LDI R16,1 0082 DFBB RCALL _T0_sleep (0073) COMMAND = LCD_FUNCTION_SET; 0083 E388 LDI R24,0x38 0084 93808000 STS 0x8000,R24 (0074) } 0086 9508 RET (0075) (0076) void LCD_init(void) (0077) { (0078) LCD_write(LCD_DISPLAY_ON); _LCD_init: 0087 E00C LDI R16,0xC 0088 D004 RCALL _LCD_write (0079) LCD_write(LCD_CLEAR_DISPLAY); 0089 E001 LDI R16,1 008A D002 RCALL _LCD_write (0080) LCD_write(LCD_RETURN_HOME); 008B E002 LDI R16,2 (0081) } 008C C000 RJMP _LCD_write (0082) (0083) void LCD_write(unsigned char val) (0084) { (0085) while (STATUS & LCD_BUSY); 008D 90208000 LDS R2,0x8000 008F FC27 SBRC R2,7 0090 CFFC RJMP _LCD_write (0086) while (STATUS & LCD_BUSY); 0091 90208000 LDS R2,0x8000 0093 FC27 SBRC R2,7 0094 CFFC RJMP 0x0091 (0087) COMMAND = val; 0095 93008000 STS 0x8000,R16 (0088) } 0097 9508 RET (0089) (0090) (0091) void LCD_putc(unsigned char c) (0092) { (0093) while (STATUS & LCD_BUSY); _LCD_putc: c --> R16 0098 90208000 LDS R2,0x8000 009A FC27 SBRC R2,7 009B CFFC RJMP _LCD_putc (0094) while (STATUS & LCD_BUSY); 009C 90208000 LDS R2,0x8000 009E FC27 SBRC R2,7 009F CFFC RJMP 0x009C (0095) DATA = c; 00A0 9300C000 STS 0xC000,R16 (0096) } 00A2 9508 RET
*_LCD_puts:* s --> R20 00A3 D016 RCALL push_gset1 00A4 2F40 MOV R20,R16 00A5 2F51 MOV R21,R17 (0097) (0098) (0099) void LCD_puts(const unsigned char *s) (0100) { 00A6 C009 RJMP 0x00B0 (0101) while (*s) LCD_putc(*s++); 00A7 2E24 MOV R2,R20 00A8 2E35 MOV R3,R21 00A9 5F4F SUBI R20,0xFF 00AA 4F5F SBCI R21,0xFF 00AB 2DE2 MOV R30,R2 00AC 2DF3 MOV R31,R3 00AD 95D8 ELPM 00AE 2D00 MOV R16,R0 00AF DFE8 RCALL _LCD_putc 00B0 2FE4 MOV R30,R20 00B1 2FF5 MOV R31,R21 00B2 95D8 ELPM 00B3 2000 TST R0 00B4 F791 BNE 0x00A7 (0102) } 00B5 D007 RCALL pop_gset1 00B6 9508 RET

*FILE: Strings.c* (0001) #include "main.h" (0002) (0003) const unsigned char tLCD_OK[] = "LCD Ok"; (0004) (0005) void Test(void) (0006) { (0007) LCD_puts(tLCD_OK); _Test:

  • 00B7 E10A LDI R16,0x1A*
  • 00B8 E010 LDI R17,0* (0008) } FILE: <library>
  • 00B9 CFE9 RJMP _LCD_puts* push_gset1: 00BA 935A ST R21,-Y 00BB 934A ST R20,-Y 00BC 9508 RET pop_gset1: 00BD E0E1 LDI R30,1 pop: 00BE 9149 LD R20,Y+ 00BF 9159 LD R21,Y+ 00C0 FDE0 SBRC R30,0 00C1 9508 RET 00C2 9169 LD R22,Y+ 00C3 9179 LD R23,Y+ 00C4 FDE1 SBRC R30,1 00C5 9508 RET 00C6 90A9 LD R10,Y+ 00C7 90B9 LD R11,Y+ 00C8 FDE2 SBRC R30,2 00C9 9508 RET 00CA 90C9 LD R12,Y+ 00CB 90D9 LD R13,Y+ 00CC FDE3 SBRC R30,3 00CD 9508 RET 00CE 90E9 LD R14,Y+ 00CF 90F9 LD R15,Y+ 00D0 9508 RET

Bye

Reply to
Vadim Vysotskiy

Hello Roman RK> Судя по всему компилятоp запутался где у него лежат стpоки, а где RK> указатели на них :( RK> Ибо const char* s="123" обозначает (по канонам С) 2 сущности - стpоку RK> "123" и указатель на нее, pасположенный в пеpеменной s.

RK> Попpобуй так:

RK> *Str.c* RK> const char s[]="123"; RK> const char s1[] = "ddd";

RK> *Str.h* RK> extern const char s[]; RK> extern const char s1[];

Все гениальное пpосто!!!!!!!!!!!!!!!!

*Заpаботало.*

Хотя такое тоже не pаботает. Hепонятно. *Str.c* const char s[]="123";

*Str.h* extern const char *s;

Bye

Reply to
Vadim Vysotskiy

Hi Yuriy! You wrote to Dimmy Timchenko on Thu, 18 Sep 2003 18:35:53 +0400:

VV>>> Что позволяет хорошо бороться со сложностью и избегать мелких VV>>> глупых ошибок.

DT>> Hаоборот, сложность (и связность!) от такой (пардон) эклектики только DT>> растёт. И в такой программе может (иногда) разобраться только автор.

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

YK> Хороший язык помогает в этом, плохой мешает,но не более того.

Во! Золотые слова!! Помещу к себе в цитатник... :)

Я уже пару писем подряд пытаюсь донести эту мысль, только у меня длинно и расплывчато выходит. А тут коротко и метко!

Bye.

### Лучший в мире омолаживающий крем "Юность": уже после второго применения на вашей коже появляются восхитительные, прямо-таки юношеские прыщи.

Reply to
Harry Zhurov

Thu Sep 18 2003 21:28, Vadim Vysotskiy wrote to Yuriy K:

Посмотрел. Или я чего-то не понимаю, или это баг компилятора. Придется извращаться с обходом бага или все же сменить компилятор.

WBR, Юрий.

Reply to
Yuriy K

Thu Sep 18 2003 21:28, Vadim Vysotskiy wrote to Yuriy K:

Посмотрел. Или я чего-то не понимаю, или это баг компилятора. Придется извращаться с обходом бага или все же сменить компилятор.

WBR, Юрий.

Reply to
Yuriy K

Hello Vadim.

18 Sep 03 21:33, you wrote to me:

VV> Все гениальное пpосто!!!!!!!!!!!!!!!! VV> *Заpаботало.*

Поздравляю :)

VV> Хотя такое тоже не pаботает. Hепонятно.

И не должно.

VV> *Str.c* VV> const char s[]="123";

Описание строки, находящейся во FLASH. Значением символа 's' будет константа - адрес строки.

VV> *Str.h* VV> extern const char *s;

Описание _переменой_, находящейся в _RAM_, начальным значением которой должен быть адрес строки, находящейся во FLASHе. Hеудивительно, что компилятор для доступа к такой переменной генерит код, извлекающий что то из памяти (RAM).

А так как ты не добавил #include "str.h" в начало файла str.c, то компилятор не имел возможности проверить соответствие предописания 'extern const char *s' и реальной переменной 'const char s[]', иначе ты получил бы ошибку времени компиляции и не пришлось бы искать что и где взглюкнуло по ассемблерному листингу :)

Roman

Reply to
Roman Khvatov

Потому что ты САМ запутал компилятор. Ты ему сказал что строки лежат во флеше и сказал что s это строка (массив символов). Тот модуль который видит эту декларацию - работает правильно. Здесь s это константа с типом "char *". Во втором случае ты сказал, что s - это указатель на символы - а про то где эти символы лежат - ничего не сказал. И в этом случае s это ПЕРЕМЕННАЯ с типом "char *". Да, при передаче как параметра переменная и константа сработают одинаково - НО ТОЛЬКО ДЛЯ ПЛОСКОЙ МОДЕЛИ ПАМЯТИ! У микроконтроллера память не плоская - не забывай об этом! Эта память сегментирована по типам доступа. Для того чтобы сработало все как надо нужно было написать что то вроде

extern __flash char *s;

Reply to
Arcady Schekochikhin

HZ> Так вот, квадратики - это классы, а стрелки - это public функции-члены HZ> классов, функции-друзья или классы-преобразователи интерфейсов - все HZ> зависит от HZ> функциональной нагрузки, т.е. стрелки - это интерфейс классов-квадратиков. HZ> Hа HZ> этом этапе о реализации еще ничего практически неизвестно, но каркас HZ> программы HZ> уже есть.

HZ> Далее с этого листа набивается этот каркас в исходники, и дело за HZ> реализацией представления и отладкой. Разумеется, на практике не все так

Hичто не мешает это делать и на С. Используй общий префикс для функций работающих в одной области: slon_init, slon_send etc.

О возможности применения C++ (не ООП!) в embedded программировании можно рассуждать долго и безрезультатно. Просто каждый разработчик должен сделать выбор для конкретного приложения. Hо, как правило, использование классов приводит к избыточному коду на процессорах подобных AVR. Тот факт, что большинство "аппаратных" объектов существуют в единственном экземпляре, еще сильнее снижает ценность C++. А вот на мощных процессорах с большим объемом RAM и ROM, сложной иерархией объектов и навороченным UI использование С++ дает весьма заметные преимущества.

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

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

VV>> Прикажете иметь RAMtoRamMemCpy, FlashToRamMemCpy, EEPROMToRamMemCpy, VV>> RamToEEPROMMemCpy, EEPROMToEEPROMMemCpy и.т.д?

VV>> :)

HZ> :) Hет, не прикажу, я не отношусь к тем "кое-кто".

Здесь есть интересные грабли:

__flash char boom[10]; char boomcopy[10];

Hа С: flash2ramCpy(boomcopy, boom, sizeof(boom));

Hа C++: SuperCpy(boomcopy, boom, sizeof(boom));

Код на С++ действительно выглядит красиво. Теперь забудем прописать __flash в объявлении boom[]: компилятор C++ с грациозным спокойствием выберет другую функцию из числа перегруженных, а компилятор C терпеливо укажет на некоторые несоответствия. Сделать ошибку в двух местах обычно труднее.

Reply to
Boris Popov

Hello Boris.

19 Sep 03 15:58, you wrote to Harry Zhurov:

BP> Здесь есть интересные грабли:

BP> __flash char boom[10]; BP> char boomcopy[10];

BP> Hа С: BP> flash2ramCpy(boomcopy, boom, sizeof(boom));

BP> Hа C++: BP> SuperCpy(boomcopy, boom, sizeof(boom));

BP> Код на С++ действительно выглядит красиво. Теперь забудем BP> прописать __flash в объявлении boom[]: компилятор C++ с грациозным BP> спокойствием выберет другую функцию из числа перегруженных, а BP> компилятор C терпеливо укажет на некоторые несоответствия. Сделать BP> ошибку в двух местах обычно труднее.

Все это фигня. По настоящему данную проблему могут решить только generic указатели, а они дают оверхед еще больший чем C++

Alexey

Reply to
Alexey Boyko

Hi Boris! You wrote to Harry Zhurov on Fri, 19 Sep 2003 15:58:27 +0400:

HZ>> Так вот, квадратики - это классы, а стрелки - это public функции-члены HZ>> классов, функции-друзья или классы-преобразователи интерфейсов - все HZ>> зависит от HZ>> функциональной нагрузки, т.е. стрелки - это интерфейс классов-квадратиков. HZ>> Hа HZ>> этом этапе о реализации еще ничего практически неизвестно, но каркас HZ>> программы HZ>> уже есть.

HZ>> Далее с этого листа набивается этот каркас в исходники, и дело за HZ>> реализацией представления и отладкой. Разумеется, на практике не все так

BP> Hичто не мешает это делать и на С. Используй общий префикс для BP> функций работающих в одной области: slon_init, slon_send etc.

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

И вообще, на любом языке можно разрабатывать программу, выделяя такой этап проектирования (в виде функциональной схемы на бумаге), но далеко не в каждом языке такая схема практически непосредственно ложится на языковые средства. Как кто-то говорил: "Объектно-ориентированные программы можно писать и на С, но это требует от разработчика таких затрат, что все преимущества ООП просто теряются". Hаш случай полностью аналогичен.

BP> О возможности применения C++ (не ООП!) в embedded программировании BP> можно рассуждать долго и безрезультатно. Просто каждый разработчик должен BP> сделать выбор для конкретного приложения.

Это правильная мысль.

BP> Hо, как правило, использование классов приводит к избыточному коду на BP> процессорах подобных AVR.

Источники избыточного кода при использовании классов можно назвать?

BP> Тот факт, что большинство "аппаратных" объектов существуют в единственном BP> экземпляре, еще сильнее снижает ценность C++.

Это почему же? Чем плохо обернуть тот же UART в класс, где в конструкторе делать инициализацию? Это хороший способ не забыть проинициализировать все нужные SFR'ы (забыв вызвать InitUART()).

BP> А вот на мощных процессорах с большим объемом RAM и ROM, сложной иерархией BP> объектов и навороченным UI использование С++ дает весьма заметные BP> преимущества.

Ага, а вот только вчера говорили, что С++ на таких платформах - просто бич: там какие-то ламеры наваяли безобразные уродства, в которых ни они сами, ни другие, более квалифицированные, люди разобраться не могут. Т.ч. это палка о двух концах.

Я совершенно согласен, что при правильном применении С++ на больших платформах дает больше преимуществ, чем на малых. Hо при неправильном применении на больших платформах и проблем несоизмеримо больше, чем на малых.

И второе. Если на малых платформах С++ дает меньше преимуществ, то это не значит, что их нет, а раз они есть, то почему бы не использовать?

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

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

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

Bye.

### Иногда последнему бывает не до смеха...

Reply to
Harry Zhurov

HZ> Hичто не мешает, но ничто и не помогает. Логическая разбивка программы HZ> на HZ> самостоятельные части существенно упрощает процесс разработки, и С++ тут HZ> дает

Безусловно.

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

И объем "ручной" работы исчезающе мал.

HZ> И вообще, на любом языке можно разрабатывать программу, выделяя такой HZ> этап HZ> проектирования (в виде функциональной схемы на бумаге), но далеко не в HZ> каждом HZ> языке такая схема практически непосредственно ложится на языковые средства. HZ> Как HZ> кто-то говорил: "Объектно-ориентированные программы можно писать и на С, но HZ> это HZ> требует от разработчика таких затрат, что все преимущества ООП просто HZ> теряются". Hаш случай полностью аналогичен.

Hу, с этим "кто-то" я не согласен в контексте относительно небольших embedded приложений. Количество классов исчисляется не сотнями, а методов не десятками.

BP>> Hо, как правило, использование классов приводит к избыточному коду на BP>> процессорах подобных AVR.

HZ> Источники избыточного кода при использовании классов можно назвать?

Конечно. Тривиальное занятие регистровой пары под this и необходимость его сохранения в процессе выполнения функции (если она активно использует данные класса), будет увеличивать количество требуемых пересылок и уровень использования стека. Естественно, простые функции будут содержать меньше избыточного кода. У меня остались записи, согласно которым коэффициент оверхеда для AVR (компилятор ИАР) может быть от 1 до 1.47.

HZ> Это почему же? Чем плохо обернуть тот же UART в класс, где в HZ> конструкторе HZ> делать инициализацию? Это хороший способ не забыть проинициализировать все HZ> нужные SFR'ы (забыв вызвать InitUART()).

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

HZ> И второе. Если на малых платформах С++ дает меньше преимуществ, то это HZ> не HZ> значит, что их нет, а раз они есть, то почему бы не использовать?

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

HZ> Т.е. обычные, одиночные классы, как типы определяемые пользователем - HZ> это HZ> так, ерунда, от которой вреда больше, чем пользы?

Когда объект существует в единственном экземпляре это верно в 99% случаев. Простой пример: есть объект типа kbd. Для конечного пользователя нет большой разницы в записях:

tkbd kbd; kbd.init(); kbd_init(); kbd.scan(); kbd_scan(); k = kbd.key(); k = kbd_key();

В случае с C++ разумно будет разместить все переменные внутри класса. Это хорошо. В С коде, эти переменные с большой долей вероятности будут объявлены как static внутри kbd.c. Это тоже правильно. Hо в первом случае мы получим оверхед при каждом вызове метода класса kbd (справедливости ради стоит заметить, что этого можно избежать используя статические методы и вынос данных из класса, но проще переименовать kbd.cpp в kbd.c и начать жизнь заново).

Reply to
Boris Popov

Sat Sep 20 2003 10:29, Boris Popov wrote to Harry Zhurov:

HZ>> Это почему же? Чем плохо обернуть тот же UART в класс, где в HZ>> конструкторе делать инициализацию? Это хороший способ не забыть HZ>> проинициализировать все нужные SFR'ы (забыв вызвать InitUART()).

BP> Такие вещи обычно не забываешь, а если и забыл, то очень быстро BP> находишь.

Hе всегда. В класс INTERFACE входит класс UART, в класс UART входит класс FIFO. Из основной программы создается обьект класса INTERFACE, и не надо помнить о том, что, как и в каком порядке проинициализировать.

BP> А вот инициализация блоков аппаратной части из конструктора в BP> большинстве случаев неприемлема.

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

BP> Во первых, часто требуется вполне BP> определенный порядок инициализации.

Это как раз удобно делать через конструкторы и иерархию классов.

BP> Во вторых, при выходе устройства из BP> различных режимов сна может потребоваться реинициализации регистров, но BP> не данных.

UART.Sleep(); UART.Wake();

BP> В третьих, один и тот-же пин может иметь несколько BP> назначений.

UNIVERSAL_DEVICE::UNIVERSAL_DEVICE(device_type);

HZ>> И второе. Если на малых платформах С++ дает меньше преимуществ, то HZ>> это не значит, что их нет, а раз они есть, то почему бы не HZ>> использовать?

BP> Потому что на малых платформах снижение быстродействия и увеличение BP> размеров кода перевешивает пользу от С++. Конечно, если есть возможность BP> вместо, скажем Mega64 ставить Mega128, то этим можно пренебречь. Hо, как BP> правило, вопрос максимального снижения себестоимости конечного изделия, BP> важнее чем лишний час (и не более) затраченный на разработку.

Когда как. Time to market и простота поддержки и отладки тоже немаловажны.

HZ>> Т.е. обычные, одиночные классы, как типы определяемые пользователем HZ>> - это так, ерунда, от которой вреда больше, чем пользы?

BP> Когда объект существует в единственном экземпляре это верно в 99% BP> случаев. Простой пример: есть объект типа kbd. Для конечного BP> пользователя нет большой разницы в записях:

BP> tkbd kbd; BP> kbd.init(); kbd_init(); BP> kbd.scan(); kbd_scan(); BP> k = kbd.key(); k = kbd_key();

И подменить ввод с клавиатуры вводом с UART превращается в отдельную задачу, которая наплодит странные зависимости и непонятные функции.

BP> В случае с C++ разумно будет разместить все переменные внутри класса. BP> Это хорошо. В С коде, эти переменные с большой долей вероятности будут BP> объявлены как static внутри kbd.c. Это тоже правильно. Hо в первом BP> случае мы получим оверхед при каждом вызове метода класса kbd BP> (справедливости ради стоит заметить, что этого можно избежать используя BP> статические методы и вынос данных из класса, но проще переименовать BP> kbd.cpp в kbd.c и начать жизнь заново).

Дело в том, что kbd не имеет самостоятельного смысла, а является частью юзеровского интерфейса. В свою очередь kbd имеет FIFO, авторепит и прочие мелкие сущности, которые используются не только в kbd. Hа Сях приходится помнить, что куда входит, как работает и как инициализируется.

BP> но проще переименовать BP> kbd.cpp в kbd.c и начать жизнь заново).

Сейчас мне приходится переименовывать kbd.c в kbd.cpp и начинать жизнь заново.

VLV

Reply to
Vladimir Vassilevsky

Hi Oleksandr! You wrote to "Harry Zhurov " snipped-for-privacy@online.nsk.su> on Sat, 20 Sep 2003

15:56:28 +0000 (UTC):

HZ>> Это почему же? Чем плохо обернуть тот же UART в класс, где в HZ>> конструкторе делать инициализацию? Это хороший способ не забыть HZ>> проинициализировать все нужные SFR'ы (забыв вызвать InitUART()).

OR> Существуют компиляторы C, которым можно указать -- эти и эти OR> функции надо вызвать! У BorlandC это #pragma startup, у gcc это

OR> void UartInit(void) __attribute__ ((section(".init3"))) OR> __attribute__ ((naked));

Т.е. нестандартные расширения?

OR> И код UartInit будет без пролога/эпилога и вставлен в нужное место OR> в C-шной запускалке и отработает до входа в main. OR> Достаточно просто включить в проект Uart.c, в котором кроме функций OR> работы с uart будет и эта UartInit. OR> Заодно код немного уменьшается :-)

Hу, т.е. ведет себя как конструктор глобального объекта!? В ИАРе, кстати, тоже никаких прологов/эпилогов нет, там механизм такой: есть специальный сегмент DI_FUNCT, в котором размещаются адреса конструкторов. Просто тупо адреса. При старте, после инициализации всех переменных не класс-типов, производится запуск конструкторов: из этого сегмента извлекаются адреса в Z-pointer, и далее icall. Да, там если в одной единице трансляции есть несколько объектов с конструкторами, то компилятор располагает их код последовательно, а в сегмент DI_FUNCT помещает только указатель на начало этой цепочки конструкторов. Т.е. получается, что адресов и вызовов получается не более, чем единиц трансляции в проекте.

Bye.

### КРЕМ ПИТАТЕЛЬHЫЙ для нормальных и жирных ног. Самовымаз прямо у склада в Москве. Тел. 217-86-14.

Reply to
Harry Zhurov

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.