|
|
  |
Стиль программирования на Си, описание функции |
|
|
|
Mar 31 2008, 10:23
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Добрый день! Столкнулся со следующей проблемой. нашол код как сделать восемь таймеров написанный Alechin Jan. Первое что кидается в глаза та это синтаксис мне непонятный. Вот к примеру прототип функции остановки тай мера: Код void Stop_Timer(IN IDX timer); ну и сама функция: Код /*--------------------------------------------------------------------------------------------*/ /* Процедура остановки таймера. */ /* Принимает: номер таймера (0 - 7). */ /* Возвращает: ничего не возвращает. */ /*--------------------------------------------------------------------------------------------*/ __monitor void Stop_Timer(IN IDX timer) { Timer[timer].Timer_Ena = TIMER_DIS; return; } Непонятно что такое IDX? Ну IN понятно, направление, очень удобно. IDX по ходу здесь беззнаковый чар. Ну и соответственно вопрос: Этот синтаксис возможен через какоето макроопределение? Может кто знает, подскажите, уверен это интерессно не только мне. Вот ещё пример Код void Start_Timer(IN IDX timer, IN WORD interval, IN pTIMER_FUNC pFunc = NULL, IN bool cycle = TIMER_ONCE); Спасибо.
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Mar 31 2008, 10:36
|

Частый гость
 
Группа: Новичок
Сообщений: 140
Регистрация: 31-01-07
Из: Челябинск
Пользователь №: 24 896

|
Цитата(sKWO @ Mar 31 2008, 16:23)  Этот синтаксис возможен через какоето макроопределение? Да, typedef, или через структуру.
Сообщение отредактировал Axxel - Mar 31 2008, 10:40
--------------------
Если боишься - не говори. если сказал - не бойся. ©
|
|
|
|
|
Mar 31 2008, 10:59
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата Этот синтаксис возможен через какоето макроопределение? да, и через макроопределение: Код #define CHAR char и через typedef Код typedef char CHAR; Но думаю что конкретно в вашем примере IDX задумывался быть перечислимым типом, объявленным через enum Код typedef enum { TIMER1 = 0, TIMER2, TIMER3, .... , TIMER_COUNT } IDX;
|
|
|
|
|
Mar 31 2008, 11:56
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(defunct @ Mar 31 2008, 14:59)  да, и через макроопределение: Код #define CHAR char и через typedef Код typedef char CHAR; Но думаю что конкретно в вашем примере IDX задумывался быть перечислимым типом, объявленным через enum Код typedef enum { TIMER1 = 0, TIMER2, TIMER3, .... , TIMER_COUNT } IDX; Ага, спасибо. Чёта мучают сомнения нащёт квалификатора перечисления Но тогда непонятно это (Его же стиль) Код OUT bool Wait_LCD_Ready(IN IDX c) Да, тогда ещё вопрос : Если возможности препроцессора ограничены, то лучше использовать typedef используя возможности компилятора? И в каких случаях предпочтительнее #define? Если кому не тяжело , приведите конкретный пример чтобы компилятор проглотил! Спасибо! Цитата(Axxel @ Mar 31 2008, 14:36)  Да, typedef, или через структуру. ПОКАЖИЦитата(aaarrr @ Mar 31 2008, 14:40)  Стиль жуткий, не надо так делать. Возможно, но мне просто интерессно. Просто в голове не укладывается как ?!
Сообщение отредактировал sKWO - Mar 31 2008, 11:58
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Mar 31 2008, 12:16
|

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

|
Цитата(sKWO @ Mar 31 2008, 18:56)  Да, тогда ещё вопрос : Если возможности препроцессора ограничены, то лучше использовать typedef используя возможности компилятора? И в каких случаях предпочтительнее #define? Во всех случаях, где можно выбирать, предпочтительнее использовать средства компилятора, а не препроцессора. Использование препроцессора нужно свести к минимуму, в идеале исключить вообще. Но на практике это не удается сделать, поэтому приходится жить с ним. По большому счету препроцессор имеет смысл использовать только для реализации условной компиляции да простеньких макроподстановок типа вставки платформенно-зависимых квалификаторов.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Mar 31 2008, 12:48
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Во всех случаях, где можно выбирать, предпочтительнее использовать средства компилятора, а не препроцессора. Использование препроцессора нужно свести к минимуму, в идеале исключить вообще. Просветите, плз, откуда такая категоричная постановка? Цитата По большому счету препроцессор имеет смысл использовать только для реализации условной компиляции да простеньких макроподстановок типа вставки платформенно-зависимых квалификаторов. Почему-то приходится применять гораздо шире. Где не вижу тонкой грани?
--------------------
aka Vit
|
|
|
|
|
Mar 31 2008, 14:08
|
Частый гость
 
Группа: Свой
Сообщений: 158
Регистрация: 27-06-05
Из: Химки, Моск.обл.
Пользователь №: 6 334

|
Так как кусок кода мой - скажу как это описано у меня (то бишь в оригинале):
// Тип переменной, занимающей 1 байт (0..255). typedef unsigned char BYTE; #define MAX_BYTE ((BYTE)-1)
// Тип переменной-указателя на переменную, занимающую байт. typedef BYTE * pBYTE;
//-------------------------------------------------------------------------------------------- // Тип индексной переменной (0..255); typedef unsigned char IDX; #define BAD_IDX ((IDX)-1)
//-------------------------------------------------------------------------------------------- // Тип переменной, занимающей 2 байта (0..65536). typedef unsigned short WORD; #define MAX_WORD ((WORD)-1)
// Макрокоманда получения значения младшего байта слова. #define LO_BYTE(word) (BYTE)(word)
// Макрокоманда получения значения старшего байта слова. #define HI_BYTE(word) (BYTE)((WORD)(word) >> 8)
// Макрокоманда формирования значения типа WORD из двух значений типа BYTE. #define MAKE_WORD(lo, hi) (WORD)(((BYTE)(lo)) | ((WORD)(hi) << 8))
// Тип переменной-указателя на переменную, занимающую 2 байта. typedef WORD * pWORD;
//-------------------------------------------------------------------------------------------- // Тип переменной, занимающей 4 байта (0..4 294 967 296). typedef unsigned long int DWORD;
// Тип переменной-указателя на переменную, занимающую 4 байта. typedef DWORD * pDWORD;
// Макрокоманда получения значения младшего слова двойного слова. #define LO_WORD(dword) (WORD)(dword)
// Макрокоманда получения значения старшего слова двойного слова. #define HI_WORD(dword) (WORD)((DWORD)(dword) >> 16)
// Макрокоманда формирования значения типа DWORD из двух значений типа WORD. #define MAKE_DWORD(lo, hi) (DWORD)(((WORD)(lo)) | ((DWORD)(hi) << 16))
//-------------------------------------------------------------------------------------------- // Тип переменной, занимающей 8 байт. typedef unsigned long long QWORD;
// Макрокоманда получения значения младшего двойного слова четверного слова. #define LO_DWORD(qword) (DWORD)(qword)
// Макрокоманда получения значения старшего двойного слова четверного слова. #define HI_DWORD(qword) (DWORD)((QWORD)(qword) >> 32)
// Макрокоманда формирования значения типа QWORD из двух значений типа DWORD. #define MAKE_QWORD(lo, hi) (QWORD)(((DWORD)(lo)) | ((QWORD)(hi) << 32))
// Тип переменной-указателя на переменную, занимающую 8 байт. typedef QWORD * pQWORD;
//-------------------------------------------------------------------------------------------- // Тип переменной-счетчика секунд. typedef DWORD SECONDS_CNTR;
|
|
|
|
|
Mar 31 2008, 14:13
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Извиняюсь, что вклиниваюсь. Цитата(sensor_ua @ Mar 31 2008, 18:48)  Просветите, плз, откуда такая категоричная постановка? Для переносимости кода. Потому, что компиляторы пишут обычно как можно ближе к стандарту языка программирования. А препроцессоры по большей части не стандартизованы (исключая может быть лишь #define и #include). И то, что работает на одном, не обязательно поймет препроцессор другого компилятора. Кроме того, препроцессор не проверяет типы данных и соответственно, оперируя его командами, можно допустить такие ошибки, которые потом "вылавливать" дольше и сложнее.
|
|
|
|
|
Mar 31 2008, 14:17
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(sKWO @ Mar 31 2008, 13:56)  Чёта мучают сомнения нащёт квалификатора перечисления Но тогда непонятно это (Его же стиль) Код OUT bool Wait_LCD_Ready(IN IDX c) Правильно мучают. Стиль действительно странный, не упирайтесь в него. Попробуйте переписать. Для арифметики гораздо удобнее объявить типы с короткими именами, и которые будут говорить сами за себя: Код typedef unsigned char U8; typedef unsigned short U16; typedef unsigned long U32; typedef unsigned long long U64;
typedef signed char S8; typedef signed short S16; typedef signed long S32;
typedef volatile unsigned char V8; typedef volatile unsigned short V16; typedef volatile unsigned long V32;
|
|
|
|
|
Mar 31 2008, 14:39
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Для переносимости кода. ... IMNHO, совсем неубедительно. Именно перепроцессором разруливаю проекты на AVR (IAR/GCC) и LPC (RVDMK/IAR), имеющие общий API. Полезные макросы пишутся, естественно, так, чтобы портировалось корректно, очень многие функции параметризуются макроопределениями по шаблонам. На работе препроцессора завязано очень много, при этом несовместимости как-то не наблюдается
--------------------
aka Vit
|
|
|
|
|
Mar 31 2008, 14:51
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(sensor_ua @ Mar 31 2008, 20:39)  IMNHO, совсем неубедительно. Именно перепроцессором разруливаю проекты на AVR (IAR/GCC) и LPC (RVDMK/IAR), имеющие общий API. Полезные макросы пишутся, естественно, так, чтобы портировалось корректно, очень многие функции параметризуются макроопределениями по шаблонам. На работе препроцессора завязано очень много, при этом несовместимости как-то не наблюдается  Уже были и неоднократно пояснения почему typedef предпочтительнее #define. Пользуйтесь поиском. Вот, например, одна из недавних веток обсуждения http://electronix.ru/forum/index.php?showt...&hl=typedef
|
|
|
|
|
Mar 31 2008, 15:23
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Уже были и неоднократно пояснения почему typedef предпочтительнее #define Спасибо, но я неплохо понимаю, что такое typedef, ну и когда может быть полезно применить #define. Если рассматривать только typedef и #define, то в основном соглашусь с Вами. Только какое это имеет отношение к переносимости кода? Цитата Объясняется все просто: код, активно использующий препроцессор сложно читать, сопровождать и отлавливать ошибки Если использование макроопределений, скажем, явно избыточно, не используются правила образования имен, то соглашусь. Также замечу, что без достойного инструмента, позволяющего "ходить" по коду не только по функциям и переменным, но и по макроопределениям, отлаживаться также может быть затруднительно. Но, если нотации определены и их придерживаются, а инструмент заточен, то всё путём.
--------------------
aka Vit
|
|
|
|
|
Mar 31 2008, 17:10
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Попробуй таки найти текстовым поиском "#define IN" и "#define OUT" или "отбросить" их как нечто ненужное  #define IN #define OUT у меня, например, в кейле используется #define __flash чтобы код из IAR не трогать
--------------------
aka Vit
|
|
|
|
|
Mar 31 2008, 17:12
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(sensor_ua @ Mar 31 2008, 23:10)  Попробуй таки найти текстовым поиском "#define IN" и "#define OUT" или "отбросить" их как нечто ненужное  #define IN #define OUT у меня, например, в кейле используется #define __flash чтобы код из IAR не трогать А вот на такое безобразие препроцессор сругаться должен. Вообще-то #undef для этих целей существует
|
|
|
|
|
Mar 31 2008, 17:26
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата А вот на такое безобразие препроцессор сругаться должен Вот и найдётся  А #undef существует для случаев когда точно знаешь, что нужно нечто переопределить. Сложнее переопределить чего-нить типа typedef enum bool{ false = 0, true = -1 };
--------------------
aka Vit
|
|
|
|
|
Mar 31 2008, 18:49
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(sensor_ua @ Mar 31 2008, 23:26)  А #undef существует для случаев когда точно знаешь, что нужно нечто переопределить. Дык Код #ifdef __flash #undef __flash #endif и всех делов  Цитата(sensor_ua @ Mar 31 2008, 23:26)  Сложнее переопределить чего-нить типа Вот именно что "сложнее", потому и надежнее.
|
|
|
|
|
Mar 31 2008, 19:07
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Гы  Мне код перебивать не нужно. Мне как раз единожды написанное под яром нужно не править - у меня текст один для кейла и яра, а ненужные квалификаторы просто выбрасываются после разруливания  Цитата потому и надежнее. Тут в примере особо изощренный случай. Такое "надёжное" лучше бы не попадалось вовсе. Пример наглого использования умолчаний Си bool is_leap(int year){ if(!(year%400))return true; if(!(year%100))return false; if(!(year%4))return true; return false; } int Get_Days_In_Month(int month, int year){ return(Days_Array[month]+(month==2)?is_leap(year):0); } при таких объявлениях bool просто веселит
--------------------
aka Vit
|
|
|
|
|
Mar 31 2008, 20:08
|
Участник

Группа: Участник
Сообщений: 37
Регистрация: 20-03-05
Пользователь №: 3 533

|
препроцессором не рекомендуется пользоваться именно из-за проблем с поиском ошибок (в основном), так как во что разворачивается макроопределение выяснить практически нереально (достоверно), отлаживаться и искать ошибки крайне неудобно. Поэтому были введены в язык средства, позволяющие практически полностью исключить использование препроцессора. Список случаев, когда препроцессор оправдан уже был озвучен.
Правда, я лично использую его неправильно, надо отучаться... Для маленьких проектов, например, для микроконтроллеров типа АВР, разницы никакой, но привычка переносится и на большие, а там проявляются все эти кажущиеся надуманными проблемы.
|
|
|
|
|
Mar 31 2008, 20:29
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата препроцессором не рекомендуется пользоваться Простите, но кем и где не рекомендуется? В стандарте? Цитата во что разворачивается макроопределение выяснить практически нереально (достоверно) ИМХО, это больше зависит от стиля написания и принятого механизма проверок. ЗЫ Во встраиваемых устройствах до недавнего времени довольно часто приходилось экономить ОЗУ при достаточном объёме памяти программ. Грамотное использование препроцессора позволяет более рационально использовать память программ, высвобождая ОЗУ.
--------------------
aka Vit
|
|
|
|
|
Mar 31 2008, 22:07
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(vshemm @ Mar 31 2008, 19:08)  Так там рекомендуется использовать препроцессор только тогда, когда это необходимо. Объясняется все просто: код, активно использующий препроцессор сложно читать, сопровождать и отлавливать ошибки. Пишем, пишем... Объявляем трехэтажный мат #define func_type_macro(arg1,arg2,arg3) ..... Применяем объявленный трехэтажный в 10-ти этажной конструкции нужное количество раз. В куске кода, размер которого никого не испугает. .......................................... Отменяем #undef func_type_macro В общем, я для себя решил, что если у меня накапливаются глобальные сложные дефайны, то это значит, что реализация идеи неправильная.
|
|
|
|
|
Apr 1 2008, 03:41
|

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

|
Цитата(sensor_ua @ Mar 31 2008, 19:48)  Просветите, плз, откуда такая категоричная постановка? Уже неоднократно на эту тему проходились, повторять не охота, воспользуйтесь поиском. Вкратце. Макроподстановка таит в себе опасность из-за того, что делается тупо, без контроля типов и контекста, в котром она производится. При этом пользователь видит одно, а получает другое. Наглядный пример тому - соседняя ветка про вычисления в макросах, когда пара лишних скобок меняла контекст выражения и вычисление выражения с этапа компиляции переносилось на этап выполнения программы, что предъявляло совершенно другие требования по потреблению стека, в частности. Причем все это происходит скрытно от пользователя, в этом и подлость. Отсутствие анализа контекста несет еще косяки - недавно обсуждали: например, фирма IAR ввела для некоторых новых чипов AVR макроопределения в заголовочных файлах ioxxx.h типа Код #define N 2 #define C 0 Теперь, если пользователь использует где-то внутри, в недрах функций (да хоть в списке аргументов прототипов) простое короткое имя N или C, то все, привет. Причем, в ряде случаев весьма неочевидно, в чем ошибка. И хорошо, если еще компилятор заругается на что-то, а то ведь может и прокатить компиляция, а в железе не работает. Вот тут попляшешь с бубном. А все потому, что препроцессор работает тупо и кладет на пространства имен, контекст выражения и делает свою работу скрытно. Некоторое время назад попался прикол (возможно байка, но все равно забавно): в исходниках, оставшихся от недавно уволенного программиста после долгой и болезненной отладки обнаужили такую сточку в одном из заголовочных файлов: Код #define TRUE FALSE // счастливой отладки, суки Список примеров можно продолжать, то повторять не хочется, уже обсуждалось не раз. Короче, макроподстановки могут приводить и приводят к труднообнаруживаемым, подлым ошибкам и несут неконтролируемое (и часто слабопредсказуемое) поведение. По этим причинам использование макроподстановок должно быть минимизировано до уровня минимально необходимого, без которого реально не обойтись. Сюда относятся простые макросы, без сложных выражений, задающие порядок условной компиляции, и другие простые замены, часто используемые при портировании. Это практически все, никаких констант, никаких макрофункций быть не должно. Цитата(sensor_ua @ Mar 31 2008, 19:48)  Почему-то приходится применять гораздо шире. Где не вижу тонкой грани? А вот мне не приходится. И все получается. Приходится применять только в рамках вышеописанного - для условной компиляции и простых подстановок при портировании. Псевдонимы типов прекрасно решаются с помощью typedef, о чем уже сказали. Макросы-литералы замечательно заменяются настоящими типизированными константами. При этом никакого оверхеда не возникает - если нет попытки взять адрес константного объекта или завести ссылку на него, то компилятор не будет его размещать в памяти. Правда, это относится к С++, где у констант по умолчанию внутреннее связывание. Но, думается, сегодня уже нет проблем использовать плюсатый компилятор. В случае с С для получения такого же поведения константные объекты придется обзывать дополнительно static. Макросы-функции без проблем заменяются встраиваемыми ( inline) функциями. Это на сегодняшний день штатно умеют уже не только С++, но и С компиляторы. По Стандарту. Если требуются какие-то нетривиальные вычисления и надо, чтобы они гарантировано производились на этапе компиляции (во избежание оверхеда), то существует мнение (и я его придерживаюсь), что такие вещи лучше вообще выполнять внешними инструментами и подсовывать компилятору уже готовые значения (потому как компилятор - не калькулятор). Через опцию -D, либо вообще поместив их в отдельный файл, который включается в проект. При использовании систем сборки (make, scons) технических трудностей не возникает никаких. Да и с оболочками тоже проблем во многих случаях нет. В любом случае не слишком разумно заставлять пыжиться целочисленный препроцессор с его 32-битной арифметикой - он отомстит (что часто и происходит).  Если все это вас не убедило, поищите в сети мнение авторитетного дяденьки Б.Страуструпа (автора языка С++), возможно, он подробнее объяснит.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 1 2008, 04:30
|

Частый гость
 
Группа: Новичок
Сообщений: 140
Регистрация: 31-01-07
Из: Челябинск
Пользователь №: 24 896

|
Цитата(sKWO @ Mar 31 2008, 17:56)  ПОКАЖИ typedef struct TYPE{ ...... ...... ...... } TYPE TYPE var; ...... Да, конечно, создание структуры созданием нового типа назвать нельзя. Правильнее говорить "структура типа type" вот что я имел ввиду. sKWO спросил, насколько я понял, "что может быть если где-то встречается нстнадартный тип"
Сообщение отредактировал Axxel - Apr 1 2008, 04:55
--------------------
Если боишься - не говори. если сказал - не бойся. ©
|
|
|
|
|
Apr 1 2008, 05:53
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Уже неоднократно на эту тему проходились, повторять не охота, воспользуйтесь поиском. Простите, но что искать? По слову макрос? Я тут довольно часто, но мимио видно всё интересное по теме пробежало. Цитата Макроподстановка таит в себе опасность Я не спорю, что пользоваться нужно уметь, а тем более таких глупых вещей, как примере от IAR, не допускать (с примерчиком познакомился ранее просматривая хедеры). Цитата По этим причинам использование макроподстановок должно быть минимизировано до уровня минимально необходимого, без которого реально не обойтись. А вот тут начинается полный субъективизм. Обратный пример - неинициализированные элементы структур и, как самые приятные  варианты, неинициализированные указатели на функции и использование указателей на структуры в качестве формальных параметров функции. Необходимость выдерживать порядок инициализации приводит к ещё более "подлым" ошибкам, чем жесткое конфигурирование с использованием макроподстановок (ну нет шаблонов в Си). Но, ИМХО, всё это имеет право на использование, если это не самоцель. Цитата Макросы-литералы замечательно заменяются настоящими типизированными константами. При этом никакого оверхеда не возникает - если нет попытки взять адрес константного объекта или завести ссылку на него, то компилятор не будет его размещать в памяти. Правда, это относится к С++, где у констант по умолчанию внутреннее связывание. К сожалению, это, IMHO, более желаемое, чем действительное. const переменная это все-таки переменная. Цитата то существует мнение (и я его придерживаюсь) опять же всё субъективно. Если не понимать ограничений препроцессора, то можно и в самом простом ошибиться. (Я, например, для редких случаев сложных константных выражений применяю тесты на интерпретаторе Ch) Цитата Но, думается, сегодня уже нет проблем использовать плюсатый компилятор К сожалению, есть. Цитата Некоторое время назад попался прикол (возможно байка Аналогично #define else ;
--------------------
aka Vit
|
|
|
|
|
Apr 1 2008, 06:16
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Пример winavr Код eeprom_read_block(&my_variable,&my_param,sizeof(my_variable)); Ну не хочу я стока писАть !!! Код #define eeread(Var,Param) eeprom_read_block(&Var,&Param,sizeof(Var)) .......................... eeread(my_variable,my_param); Интересует субъективное мнение: оправдано ли в данном случае применение макро?
|
|
|
|
|
Apr 1 2008, 06:30
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(sensor_ua @ Apr 1 2008, 08:53)  Простите, но что искать? По слову макрос? Я тут довольно часто, но мимо видно всё интересное по теме пробежало. Я расскажу интересное!  Не далее как вчера час искал отсутствие фигурных скобок в макросе из двух команд, который использовался в if /else. На фоне какой-то непонятной потери синхронизации с JTAGом повеселился по полной программе. Сам себе клоун. Тем не менее сложные макросы использую, вариант с функциями inline не перекрывает всех возможных ситуаций. Использую один раз созданную конструкцию для организации доступа к переменным в протоколе обмена и переношу из проекта в проект, один раз отладив стиснув зубы  Но создавать такое в каждом проекте - упаси Бог. Для того, чтобы было понятно, о чем разговор, пример текста описания переменных. В поддержку протокола в объект 'system' включаются 4 переменных со своими именами, и функциями, вызываемыми при чтении и записи. Все это разворачивается в массивы строк и указателей на функции. Добавление переменной в протокол происходит за минуту максимум. Код IMPL_PROLOG(system) IMPL_VARIABLE(system, 0, "HTI 16V hose pumps", IMPL_GET dpr->tx_value=(long)COUNT_ELEMENTS(system_names); return;, IMPL_SET READ_ONLY ) IMPL_VARIABLE(system, 1, "Firmware version", IMPL_GET dpr->name=version; return;, IMPL_SET READ_ONLY ) IMPL_VARIABLE(system, 2, "Objects quantity", IMPL_GET dpr->tx_value=(long)OBJECTS_QUANTITY; return;, IMPL_SET READ_ONLY ) IMPL_VARIABLE(system, 3, "Heartbeat Period,s", IMPL_GET GET_HEARTBEAT, IMPL_SET SET_HEARTBEAT ) IMPL_EPILOG()
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Apr 1 2008, 06:33
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(sensor_ua @ Apr 1 2008, 09:53)  К сожалению, это, IMHO, более желаемое, чем действительное. const переменная это все-таки переменная. Еще добавлю примерчик Код static PROGMEM char array[3] = {'A','B','C'}; ................................ char a; a = array[0]; Winavr сделает a='A' , поскольку array[0] рассматривается как константное выражение. Сделают ли то же самое компилеры с услужливым сервисом "чтения флеша" - не уверен.
|
|
|
|
|
Apr 1 2008, 07:01
|

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

|
Цитата(sensor_ua @ Apr 1 2008, 12:53)  А вот тут начинается полный субъективизм. Обратный пример - неинициализированные элементы структур и, как самые приятные  варианты, неинициализированные указатели на функции и использование указателей на структуры в качестве формальных параметров функции. Необходимость выдерживать порядок инициализации... Нет, это другое. Это вы про элементы низкоуровневого программирования, которые сопряжены необходимостью внимательно следить за соблюдением правил. Но это, повторяю, другое - тут у вас все на виду, анализ кода сразу показывает гнилое место. Сразу видно, где потенциальные грабли - адресная арифметика, операции с указателями, инициализация аргегатных объектов, ручные преобразования типов и т.д., этим вещам надо уделять повышенное внимание. В то время как с макроподстановкой пакостное поведение скрыто от непосредственного взгляда, и негативные последствия могут вылезать совсем в другом месте. Цитата(sensor_ua @ Apr 1 2008, 12:53)  К сожалению, это, IMHO, более желаемое, чем действительное. const переменная это все-таки переменная. Вернее - это констатный объект. Если нет необходимости размещать его в памяти (не берется адрес и нет ссылки на него), то никакой вменяемый компилятор этого делать не будет - именно для этой возможности в том же С++ специально ввели правило, согласно которому константные объекты имеют внутреннее связывание... Хорошо, не верите, давайте проверим. Поскольку тут форум по AVR, то на нем и будем тренироваться. Код: Код // file: slon.cpp
const int a = 10;
int f(int x) { return x + a; } Комилятор - какой-то от IAR. v4.хх. Не суть важно. Результат: Код const int a = 10; In segment CODE, align 2, keep-with-next int f(int x) ??f: { return x + a; 00000000 5F06 SUBI R16, 246 00000002 4F1F SBCI R17, 255 00000004 9508 RET } Как видим, все замечательно получилось, ничего в памяти не размещается, никаких обращений к памяти, ессно, нет. Это в режиме ++. Отключаем его - в С режиме результат: Код In segment NEAR_I, align 1, keep-with-next REQUIRE `?<Segment init: NEAR_I>` const int a = 10; a: DS 2 REQUIRE `?<Initializer for a>` In segment CODE, align 2, keep-with-next int f(int x) f: { return x + a; 5F06 SUBI R16, 246 4F1F SBCI R17, 255 9508 RET } In segment NEAR_ID, align 1, keep-with-next `?<Initializer for a>`: 000A DW 10 Да, тут, как и положено, константа 'a' размещена в памяти (и инициализатор тоже съест свою часть в сегменте инициализаторов), потому что компилятор не имеет права этого не сделать - в С константные объекты имеют по умолчанию внешнее связывание и к ним может производиться обращение из других единиц компиляции. В этом случае линкер будет материться на отсутствие объекта. Но даже в этом случае компилятор, видя значение констатнты, не стал городить обращение к ней, а сгенерил более короткий эффективный код. Поведение можно сделать как в ++ варианте, снабдив объявление констатны квалификатором static: static const int a = 10; Результат аналогичен первому варианту: Код static const int a = 10; In segment CODE, align 2, keep-with-next int f(int x) f: { return x + a; 5F06 SUBI R16, 246 4F1F SBCI R17, 255 9508 RET } Думается, что написать ключевое слово 'static' не является слишком обременительным. Кстати, сделать в С++ поведение констант аналогичным С-шному можно сделать с помощью объявления их как 'extern'. Результат компиляции приводить не буду, поверьте, оно точно соотвествует вышеприведенному С без 'static'. Цитата(sensor_ua @ Apr 1 2008, 12:53)  К сожалению, есть. И в чем они состоят? Для AVR хоть коммерческий IAR, хоть безплатный AVR-GCC давно уже поддерживают почти все фичи С++ (за исключением тяжелых, которые реально применять на AVR смысла нет).
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 1 2008, 08:17
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Но это, повторяю, другое Дальше бессмысленно обсуждать - лучше/хуже, видно/невидно и применять/не применять, рекомендуется/нерекомендуется суть разные вещи. Цитата никакой вменяемый компилятор этого делать не будет для начала вменяемые компиляторы не будут ругаться на передачу в качестве фактического параметра функции const переменной, когда формальный параметр объявлен не const. В "прямоугольных" вариантах применения (таких как Вы показали) действительно интеллект компилятора может быть на высоте. Цитата Думается, что написать ключевое слово 'static' не является слишком обременительным. Вы не поверите  - использую описанные Вами приёмы и не стесняюсь Цитата И в чем они состоят? Насчёт одинаково хорошо http://www.klen.org/Projects/Embeded-gnu-t...last_build.htmlhttp://www.klen.org/Projects/Embeded-gnu-t...gcc-cpp-how.txtА насчёт нюансов использования, например, смотрим пост 7 http://electronix.ru/forum/index.php?showt...;p=247899&#Не то, чтобы я против использования плюсов - этим нужно заниматься(С) Но как раз реализации "плюсовости" у компиляторов гораздо более различны, нежели отклонения в работе их препроцессоров.
--------------------
aka Vit
|
|
|
|
|
Apr 1 2008, 09:28
|

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

|
Цитата(sensor_ua @ Apr 1 2008, 15:17)  Дальше бессмысленно обсуждать - лучше/хуже, видно/невидно и применять/не применять, рекомендуется/нерекомендуется суть разные вещи. Не следует путать приятное с полезным. В одном случае имеем объективные трудности из-за использования низкоуровневого кодирования, которое требует повышенного внимания - это сродни кодированию на ассеблере, за всем надо внимательно следить. Обратная сторона этого - высокая эффективность (малый размер, быстродействие) кода. В другом случае сами себе раскладываем грабли. Которые можно обойти, используя более адекватные средства, получив результат не хуже. Каждый случай использования препроцессора должен быть четко обоснован, и на основании этого сделан вывод, что иные пути дают худший результат или вообще не дают такового. Цитата(sensor_ua @ Apr 1 2008, 15:17)  для начала вменяемые компиляторы не будут ругаться на передачу в качестве фактического параметра функции const переменной, когда формальный параметр объявлен не const. Вы про это: Код const int a = 10; int b;
int g(int x, int y);
int main() { g(a, b); } ? Если да, то вот результат: Код int main() main: { g(a, b); .... LDI R30, LOW(b) .... LDI R31, (b) >> 8 8120 LD R18, Z 8131 LDD R19, Z+1 E00A LDI R16, 10 E010 LDI R17, 0 ........ CALL ??g } Никакой ругани нет. И это не странно, если подумать и понять, что компилятор вполне адекватно оценивает ситуацию и не видит ничего опасного в таком вызове функции. Да и что тут может быть опасного? Ведь передача аргумента делается по значению. Вот если бы была попытка передать указатель (или ссылку) на константный объект, то это была бы ошибка, т.к. такая ситуация может привести к попытке изменить констатный объект внутри вызываемой функции. Но компилятор этого и не разрешает. А если какой-то компилятор разрешает, то это просто его баг и ничего более. Все эти правила стандартизованы и исходят из здравого смысла. Что не так? Цитата(sensor_ua @ Apr 1 2008, 15:17)  В "прямоугольных" вариантах применения (таких как Вы показали) действительно интеллект компилятора может быть на высоте. Хорошо, покажите свои "треугольные" или "круглые" варианты, где в подобной ситуации (с константами) компилятор облажается. Давайте пример в студию, посмотрим его. Интересно. Цитата(sensor_ua @ Apr 1 2008, 15:17)  Вы не поверите  - использую описанные Вами приёмы и не стесняюсь Тогда не понятно, какую точку зрения отстаиваете. Цитата(sensor_ua @ Apr 1 2008, 15:17)  И что конкретно там не так? Я никакого криминала не увидел. Особенно, в части константных объектов - там вообще ни слова не нашел про это. Может, плохо искал?  Цитата(sensor_ua @ Apr 1 2008, 15:17)  А насчёт нюансов использования, например, смотрим пост 7 http://electronix.ru/forum/index.php?showt...=247899�И что? Манглинг имен - обычное дело в С++, жить реально не мешает. И опять совсем не понял, как это мешает использовать константные объекты вместо макросов? Цитата(sensor_ua @ Apr 1 2008, 15:17)  Но как раз реализации "плюсовости" у компиляторов гораздо более различны, нежели отклонения в работе их препроцессоров. Реализации плюсовости у компиляторов отличаются по одной шкале - у одних поддерживаемых фич языка больше, у других - меньше. Но сами фичи если поддерживаются, то поведение дают одинаковое, т.к. есть на все это Стандарт. А вот на препроцессор стандарта нет, препроцессоров действительно существует некоторое количество, и совместимость у них скорее согласно традициям, нежели стандартам.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 1 2008, 12:40
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Lem @ Mar 31 2008, 22:08)  как во что разворачивается макроопределение выяснить практически нереально (достоверно) Как правило препроцессор идёт отдельным исполняемым файлом и/или у компилятора есть соответствующий ключик "выполнить только препроцессор". И можно получить выход препроцессора и всё поразглядывать. Да, очень много чего можно затолкать в enum-ы, inline-функции и т.п. Да, в С++ есть ссылки, позволяющие уменьшить использование указателей и связанных с неправильным их применением ошибок (ударение на слове "неправильным", а не на слове "применением"). И т.д. и т.п. Но, извините, #define TRUE FALSE и #define SQR(x) x * x это примеры вредительского и безграмотного применения макросов, а не их генетической ущербности. Но на их базе строится рекомендация "использование макросов следует уменьшать в идеале до нуля", что, на мой взгляд, неправильно, как неправильны и рекомендации не использовать указатели (а почему тогда в стандарте оставили не только условную компиляцию, но и функциональные макросы, склейку и подстановку аргументов и оставили указатели?) Так же как и с goto, который я использую редко и на форумах иногда сам привожу примеры, как можно обойтись без goto и при этом и сгенерированный код не растёт, и читаемость улучшается, но который я инода таки использую - так же и с макросами: Используйте, не бездумно, голова дана именно для выбора нужного средства языка!(Кстати, а какое средство языка можно использовать бездумно? Знаменитые примеры "индусского" кода написаны и без макросов, и без gotoи часто вообще на яве, изначально "лишённой недостатков С/С++")Правильно и в нужном месте применённые макросы, на мой взгляд, только улучшают (не слишком хорошо формализуемый и очень вкусовой параметр) читаемость кода. Кончено, для людей, умеющих с ними обращаться (та же проблема с указателями). Огрызок .h Код typedef WINAPI void (*DlPortWritePortUchar_t) (unsigned port, uint8_t d); typedef WINAPI uint8_t (*DlPortReadPortUchar_t) (unsigned port); typedef WINAPI void (*DlPortWritePortBufferUchar_t) (unsigned port, const uint8_t *pd, int len);
class lpt_dlportio_t : public lpt_io_t { public: lpt_dlportio_t(unsigned _base); ~lpt_dlportio_t();
virtual uint8_t read(rd_offset offs); virtual void write(wr_offset offs, uint8_t d); virtual void write_data(const uint8_t *pd, int len);
private: HINSTANCE hdlportio; #define _DL_PTR(_f_) _f_##_t _f_##_P _DL_PTR(DlPortWritePortUchar); _DL_PTR(DlPortReadPortUchar); _DL_PTR(DlPortWritePortBufferUchar); #undef _DL_PTR }; // class lpt_dlportio_t Огрызок .cpp Код lpt_dlportio_t::lpt_dlportio_t(unsigned _base) : lpt_io_t(_base), hdlportio(NULL) { hdlportio = LoadLibrary("DLportIO.dll"); if (hdlportio == NULL) throw error_win32_t(E_INVHARD, "Can't load port access library `DLportIO.dll'");
#define _DL_LOAD(_f_)\ do {\ _f_##_P = (_f_##_t)GetProcAddress(hdlportio, #_f_);\ if(_f_##_P == NULL)\ throw error_win32_t(E_INVHARD, "Can't load port access library `DLportIO.dll'"); \ } while(0)
_DL_LOAD(DlPortWritePortUchar); _DL_LOAD(DlPortReadPortUchar); _DL_LOAD(DlPortWritePortBufferUchar); #undef _DL_LOAD
} // lpt_dlportio_t::lpt_dlportio_t И не говорите мне, что этот текст надо переписать без макросов для облегчения чтения и сопровождения (представим себе, что понадобилось добавить ещё одну функцию из dlportio.dll и/или изменить обработку ошибки - в каком случае надо больше до-/пере-писывать руками и где при этом больше шансов ошибиться в одной из ветвей - в варианте с макросами или с прямым текстом? И ещё пример на эту тему http://www.telesys.ru/wwwboards/mcontrol/1...es/314290.shtml
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 1 2008, 13:07
|
Участник

Группа: Участник
Сообщений: 37
Регистрация: 20-03-05
Пользователь №: 3 533

|
одним из авторитетов для меня является Герб Саттер,ну, там ещё куча умных опытных людей, которые много поработали с БОЛЬШИМИ системами и знают, какова цена тех или иных ошибок при отладке и сопровождении проектов, создаваемых коллективами за длительные сроки и большие деньги
|
|
|
|
|
Apr 1 2008, 13:11
|

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

|
Цитата(SasaVitebsk @ Apr 1 2008, 19:48)  На данном этапе не планирую отказываться от этого средства языка. Возможно потом пересмотрю данное решение. Да никто и не призывает отказываться от препроцессора и макросов - это просто нереально, т.к. не существует адекватной замены всем средствам и во всех ситуациях. Речь о том, что надо стремиться свести к минимуму его (препроцессора) использование и использовать по возможности только такие варианты, которые не несут подводных граблей. Во всяком случае крайне желательно исключить повсеместное использование макросов препроцессора в качестве литералов и функций. Цитата(SasaVitebsk @ Apr 1 2008, 19:48)  В связи с этим вопрос. Как в IAR просмотреть результаты работы препроцессора. Например где можно увидеть результаты вычисления констант? В ряде случаев это реально помогло бы.  Да, такое средство очень кстати и меня не раз выручало. Ключик: Код --preprocess=[c][n][l] file|directory Preprocessor output c Include comments n Preprocess only l Include #line directives
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 1 2008, 13:37
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Не следует путать приятное с полезным... Не знаю о чём Вы, но я о том, что заявления, что что-то НЕ РЕКОМЕНДУЕТСЯ, стОит подкреплять не столько личным мнением/опытом (нисколько не умаляю Ваших достоинств), сколько какими либо ссылками на Стандарт. Цитата Тогда не понятно, какую точку зрения отстаиваете Я считаю, что препроцессор - нужный и полезный инструмент. Да, огульное его применение не приветствуется, так как существует много описанных выше причин, по которым возникают ошибки. Я для супа использую ложку, а для бифштекса - нож и вилку. Я могу объяснить, почему вилкой есть суп не получится, но мне трудно объяснять ребёнку, почему нельзя есть бифштекс ложкой. typedef и применение текстовых замен действительно очень похожи, и если нужен тип, то typedef предпочтительнее, чем текстовая подстановка, но ведь не просто так - они отличаются - свойства у typedef имеются, которых у текстовых подстановок нет. Препроцессор позволяет манипулировать с именами (склейка, подмена, удаление, индексация), что при отсутствии поддержки шаблонов на уровне самого языка является необходимым дополнением. Что касается сложных выражений, то применение препроцессора ограничено его ограниченными возможностями и он действительно не предупреждает о переполнениях и прочих глупостях. Но сложность бывает разная - где мы в уме считаем, где не прочь в столбик, а где и калькулятора не хватает. Потому рекомендации по отказу от применения препроцессора при любой возможности считаю необоснованными. Цитата Хорошо, покажите свои "треугольные" или "круглые" варианты, где в подобной ситуации (с константами) компилятор облажается. Давайте пример в студию, посмотрим его. Интересно. Что касается константных объектов приведу пример, который говорит в пользу препроцессора как удобного инструмента Это выдаёт ошибку в IAR Код typedef void (MY_FOO_TYPE)(); typedef struct { int a; int b; int c; MY_FOO_TYPE * foo; } mytype;
void myfoo1(void); void myfoo2(void); #define sDefault_Value1 { \ 777, \ 0, \ 55, \ &myfoo1 \ } #define sDefault_Value2 { \ 111, \ 222, \ 3333, \ &myfoo2 \ }
const int def1_aa = 777; const int def1_bb = 0; const int def1_cc = 55; const MY_FOO_TYPE * def1_foo = &myfoo1;
mytype a = {0};
const mytype aaa = sDefault_Value1; const mytype bbb = sDefault_Value2; volatile int i; int main(void){ while(1){ if(i == a.a){ i = a.b; a = aaa; // ошибки нет a.a = def1_aa; a.b = def1_bb; a.c = def1_cc; a.foo = def1_foo;//!!!ошибка //Error[Pe513]: a value of type "void () const *" cannot be assigned to an entity of type "void () *" D:\avrtst\avrtst\main.c 44
} else{ i = a.a; a = bbb; }
} return 0; }
void myfoo1(void){ ; } Наверно правильно выдаёт Цитата А вот на препроцессор стандарта нет п.6.10 http://upload.caxapa.ru/standards/ansi_c-i...c_9899-1999.pdfЦитата Да, такое средство очень кстати и меня не раз выручало. Ключик: Отдельное спасибо
--------------------
aka Vit
|
|
|
|
|
Apr 1 2008, 13:50
|

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

|
Цитата(ReAl @ Apr 1 2008, 19:40)  Как правило препроцессор идёт отдельным исполняемым файлом и/или у компилятора есть соответствующий ключик "выполнить только препроцессор". Это где такое правило? В GCC? Рад за него. В IAR с некоторых пор появился ключик. А вот в используемом мной сейчас VDSP такого удовольствия нет (не нашел). Т.ч. тут как повезет. Цитата(ReAl @ Apr 1 2008, 19:40)  Да, очень много чего можно затолкать в enum-ы, inline-функции и т.п. Именно!  И все, что можно туда затолкать, не надо пихать в макросы. Об этом и спич. Цитата(ReAl @ Apr 1 2008, 19:40)  Но, извините, #define TRUE FALSE Да это я вообще в качестве хохмы привел, не апеллируя к этому примеру, как к аргументу. Просто этот пример наглядно демонстрирует мощь препроцессора как дестуктивного средства, только и всего. Цитата(ReAl @ Apr 1 2008, 19:40)  это примеры вредительского и безграмотного применения макросов, а не их генетической ущербности. Как насчет вышеприведенного примера про Код #define I 7 #define N 2 #define C 0 ? А ведь это не лохи какие-то делали, а вполне серьезная и уважаемая фирма IAR Systems, которая выпускает очень достойные продукты. Замечательные грабли. Замечательный пример той же самой деструктивной мощи. Да, препроцессор обладает известной гибкостью в силу своих свойств по текстовой подстановке, но это палка о двух концах. Не стоит злоупотрелять ею. Имхо, "генетическая ущербность" препроцессора в том, что он делает свою работу тупо, без анализа, не обращая внимания на простнаства имен и прочий контекст, о чем уже в этой же ветке было не раз говорено. Цитата(ReAl @ Apr 1 2008, 19:40)  Но на их базе строится рекомендация "использование макросов следует уменьшать в идеале до нуля", Да. Но идеал недостижим. Поэтому препроцессор останется. Цитата(ReAl @ Apr 1 2008, 19:40)  (а почему тогда в стандарте оставили не только условную компиляцию, Потому, что для нее нет адекватной замены. Цитата(ReAl @ Apr 1 2008, 19:40)  но и функциональные макросы, склейку и подстановку аргументов Совместимость и преемственность. Попробуй убери что-нить из этого - миллионы строк кода уже написанного, отлаженного и работающего кода сразу перестанут компилироваться. Цитата(ReAl @ Apr 1 2008, 19:40)  и оставили указатели?) Указатели из другой оперы, не надо все в кучу валить. Еще спроси (ехидно так), зачем оставили ассемблер - там тоже можно при невнимательном обращении наворотить.  Цитата(ReAl @ Apr 1 2008, 19:40)  Так же как и с goto, который я использую редко Реально есть одна ситуация, где без него геморно - выход из вложенного цикла. Вроде все, больше не знаю (навскидку). Из-за этого оный оператор и оставили в языке. Цитата(ReAl @ Apr 1 2008, 19:40)  так же и с макросами: Используйте, не бездумно, голова дана именно для выбора нужного средства языка! Осталось найти, как добраться до головы иаровских разрабов, соорудивших макросы, приведенные выше.  Если есть возможность разложить грабли - они будут разложены. Раньше или позже, чаще или реже. Желательно, чтобы это было реже. Для этого использование препроцессора надо свести к минимуму, о чем только и речь. Никто не призывает отказаться от него вообще - это, повторяю, нереально. Чего в крайности кидаться. Цитата(ReAl @ Apr 1 2008, 19:40)  (Кстати, а какое средство языка можно использовать бездумно? Знаменитые примеры "индусского" кода написаны и без макросов, и без gotoи часто вообще на яве, изначально "лишённой недостатков С/С++") Коренное отличие многих среств языка от средств препроцессора в том, что с ними код читается без подводных граблей. Сразу видно, как используется средство, сразу понятно, что тут можно ожидать. А вот с препроцессором оно несколько не так. Цитата(ReAl @ Apr 1 2008, 19:40)  И не говорите мне, что этот текст надо переписать без макросов для облегчения чтения и сопровождения (представим себе, что понадобилось добавить ещё одну функцию из dlportio.dll и/или изменить обработку ошибки - в каком случае надо больше до-/пере-писывать руками и где при этом больше шансов ошибиться в одной из ветвей - в варианте с макросами или с прямым текстом? Это большой вопрос, как лучше, пример не убеждает. Насчет руками - про рефакторинг слышал? Кроме того, тут пример очень осторожного использования - определение макроса лежит прямо тут же, все перед глазами. Но не дай бог кто-нить вздумает использовать такое же имя _DL_PTR в своей программе. Будет удивлен.  Т.ч. тут тоже есть, что обсудить. Цитата(ReAl @ Apr 1 2008, 20:40)  Ну в такой формулировке - с указанием где именно и без абсолютной категоричности - можно согласиться :-) Но ведь обычно идёт разговор "запретить и всё тут, так как это источник ошибок". Это где это сказано, что "запретить" и все тут? Сказано было, свести к минимуму.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Apr 1 2008, 14:43
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(dxp @ Apr 1 2008, 16:50)  Осталось найти, как добраться до головы иаровских разрабов, соорудивших макросы, приведенные выше.  Да фиг с ними, с разработчиками. Ну достучишься, и "миллионы строк кода уже написанного, отлаженного и работающего кода сразу перестанут компилироваться"  Код #ifdef I #undef I #endif #ifdef N #undef N #endif #ifdef C #undef C #endif Добавлять сразу после #include <ioavr.h> Кстати, эти же грабельки перекочевали и в заголовочники avr-libc.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 1 2008, 14:51
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(dxp @ Apr 1 2008, 15:50)  Это где такое правило? В GCC? Рад за него. Во-первых, "как правило" != "существует правило", во вторых, из правил есть исключения. Необходимость выдавать ассемблерный листинг тоже нигде не прописана, но как правило эта возможность имеется. На моей памяти большинство компиляторов позволяли просмотреть выдачу препроцессора. Цитата(dxp @ Apr 1 2008, 15:50)  Как насчет вышеприведенного примера про Код #define I 7 #define N 2 #define C 0 Ну что я скажу... У gcc в этом месте SREG_I, SREG_N и так далее. Солидная фирма, не солидная - а бывает и на старушку прорушка. Цитата(dxp @ Apr 1 2008, 15:50)  Потому, что для нее нет адекватной замены. Я спросил не "почему условную компиляцют оставили", а "почему вместе с ней оставили функциональные макросы, склейку, ..." Цитата(dxp @ Apr 1 2008, 15:50)  Совместимость и преемственность. Попробуй убери что-нить из этого - миллионы строк кода уже написанного, отлаженного и работающего кода сразу перестанут компилироваться. Какого кода??? С++ ? А какого лешего компилировать С-код С++-компилятором? Или тогда решили, что всё, С-компиляторы больше никто не будет писать и даже развивать, и поэтому для сопровождения С-кода надо в С++ оставить явно вредные вещи? Могли бы в С++ режиме и устранить "огромный недостаток". Тем более, что в мелких, неочевидных и местами обидных случаях С++ таки сильно отличается от С (например, литерал 'я' в языке С имеет тип int а в С++ имеет тип char). Цитата(dxp @ Apr 1 2008, 15:50)  Указатели из другой оперы, не надо все в кучу валить. Еще спроси (ехидно так), зачем оставили ассемблер - там тоже можно при невнимательном обращении наворотить.  А где ассемблер в стандарте языков С/С++ ??? Цитата(dxp @ Apr 1 2008, 15:50)  Для этого использование препроцессора надо свести к минимуму, о чем только и речь. Никто не призывает отказаться от него вообще - это, повторяю, нереально. Чего в крайности кидаться. Коренное отличие многих среств языка от средств препроцессора в том, что с ними код читается без подводных граблей. Сразу видно, как используется средство, сразу понятно, что тут можно ожидать. А вот с препроцессором оно несколько не так. Так в том-то и дело, что агитаторы за предельную минимизацию применения указателей а то иногда и тернарной операции говорят то же самое - "неочевидно, непонятно, в отличие от массивов, ссылок и if/else". И часто при этом столь же категоричны, как и в случае с goto - "не должно быть вообще", "по нашему стандарту предприятия goto запрещены". Так что кидаюсь в крайности не я. Цитата(dxp @ Apr 1 2008, 15:50)  Это большой вопрос, как лучше, пример не убеждает. Насчет руками - про рефакторинг слышал? Это как - я добавляю в описание класса поле, а в конструкторе сразу по кнопочке "сделайте мне красвиво" сгенерируется для него Код нужное_имя = (нужный_тип)GetProcAddress(hdlportio, нужная_строка); if(нужное_имя == NULL) throw error_win32_t(E_INVHARD, "Can't load port access library `DLportIO.dll'"); Или всё же придётся ручками это делать? Цитата(dxp @ Apr 1 2008, 15:50)  Кроме того, тут пример очень осторожного использования - определение макроса лежит прямо тут же, все перед глазами. Но не дай бог кто-нить вздумает использовать такое же имя _DL_PTR в своей программе. Будет удивлен.  Т.ч. тут тоже есть, что обсудить. Получит предупреждение о переопределении и сразу увидит что и где конфликтует. Если код пишет так, что предупреждения валят десятками на каждый файл и поэтому отключил без разбору все предупреждения - то не помогут никакие ограничения - наксоячит. Цитата(dxp @ Apr 1 2008, 15:50)  Это где это сказано, что "запретить" и все тут? Сказано было, свести к минимуму. Ну, ты не самый бескомпромиссный борец с препроцессором :-) И то считаешь, что "в идеале исключить вообще". Я же считаю, что "в идеале" его может и неплохо бы заменить чем-то более грамотным, но оно почти наверняка будет более сложным и менее удобным (эти два фактора могут не уменьшить глюкодромистость, а увеличить), поэтому пусть лучше остаётся как есть и как с любым инструментом - его нужно знать, чтобы пользоваться правильно. А для этого нужно пользоваться. А чтобы было меньше отрезанных пальцев - не убирать с кухни ножи, а учиться ими пользоваться тогда, кода это надо и не махать ими, показывая, как летали листья. Но не говорить, что есть открывашки, консервные ножи и хлеб можно купить уже нарезанным, поэтому применение ножей Цитата(dxp @ Mar 31 2008, 14:16)  нужно свести к минимуму, в идеале исключить вообще. Но на практике это не удается сделать, поэтому приходится жить с ним. По большому счету ... имеет смысл использовать только в затупленном виде для простеньких вещей типа намазывания масла. Просто нужно учить тому, что каждый инструмент нужно использовать с умом. А не рекомендовать "минимизировать до отсутствия", так как пока научитесь - можете пораниться. А уж сколько людей ими убито... Цитата(Сергей Борщ @ Apr 1 2008, 16:43)  Кстати, эти же грабельки перекочевали и в заголовочники avr-libc. Разве? Там ведь в common.h сидят SREG_* Хотя, мне кажется, желание "облегчить переход с IAR" у них инода избыточное, могли и добавить односимвольные.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 1 2008, 20:44
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(dxp @ Apr 1 2008, 16:50)  А вот в используемом мной сейчас VDSP такого удовольствия нет (не нашел). Т.ч. тут как повезет. Самостоятельные препроцессоры "C" не редкость, да и тем-же GCC прогнать можно... Посему на везение уповать совсем незачем  . Цитата(ReAl @ Apr 1 2008, 17:51)  А какого лешего компилировать С-код С++-компилятором? А почему-бы и нет? Есть свои приятственные фичи в C++ компиляторах и для почти сишного кода. А как, например в смешанном коде без немерянных извращений работать с плюсовым кодом? Лично я в большинстве случаев так и поступаю. Цитата(ReAl @ Apr 1 2008, 16:40)  Но ведь никто не рекомендует отказаться от них и начать писать p = p + 1; Или уже рекомендуют?  Рекомендуют  С полгода назад на форуме проскаивала ссылка на переводную статью по "правильному стилю" именно с такой рекомендацией. У многих сей опус вызвал одобрение  . Я естественно, не мог смолчать - возражал...
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 1 2008, 22:17
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(zltigo @ Apr 2 2008, 00:44)  Рекомендуют   А мне так понравилось. По сравнению с Паскалем, к примеру.  А с другой стороны - сомневаешься, напиши так, чтобы сомнений не было.  Всётаки выбор - великое дело. Зачем самих себя ограничивать изначально. Сталкиваешься с граблями (своими), анализируешь, применяешь так, чтобы в дальнейшем не наступать. Так свой подход вырабатывается. А написание прог для совместного использования, или для постороннего использования, - всётаки сложная задача требующая своих подходов. Я, чаще всего, заимствованное переписываю под себя. Тем не менее, с учётом данной дискуссии, сделаю выводы и обдумаю все ваши предложения. Попробую переосмыслить. А то действительно проблемы некоторые уже возникали. А всётаки было бы неплохо иметь элемент языка, который бы определял константы под которые гарантированно не выделяется память и которые вычисляются строго на этапе компиляции. Для IBM, экономия памяти не стоит как задача, а вот для мелкоAVRов былобы неплохо.
|
|
|
|
|
Apr 2 2008, 06:58
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(SasaVitebsk @ Apr 2 2008, 01:17)  По сравнению с Паскалем, к примеру.  Анафема тому Паскалю, который не поддерживает функции inc(N,M), dec(N,M)  А насчет пред/пост инкремента, например, действительно генератор граблей. Но пользоваться приятно... до тех пор, пока есть уверенность в адекватной трансляции.
|
|
|
|
|
Apr 2 2008, 09:58
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(ReAl @ Apr 1 2008, 15:40)  Но ведь никто не рекомендует отказаться от них и начать писать p = p + 1; Или уже рекомендуют?  Delphi'сты рекомендуют  Цитата(dxp @ Apr 1 2008, 15:50)  Как насчет вышеприведенного примера про Код #define I 7 #define N 2 #define C 0 ? Я еще люблю применять #define K 1024 #define M K*K Просто кому придет в голову объявить переменную ОДНОЙ ЗАГЛАВНОЙ буквой? Цитата(SasaVitebsk @ Apr 2 2008, 00:17)   А мне так понравилось. По сравнению с Паскалем, к примеру.  ++ / -- - просто создан для индексации массивов. тоже неплохо смотрится в условиях. а повсеместно тыкать ++ / -- ни ни, я отдаю предпочтение p += 1 вместо ++;
|
|
|
|
|
Apr 2 2008, 11:55
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(zltigo @ Apr 1 2008, 22:44)  Самостоятельные препроцессоры "C" не редкость, да и тем-же GCC прогнать можно... Посему на везение уповать совсем незачем  . Тут можно спорить о возможном несовпадении (один из них или оба могут не польностью соответствовать стандрату и проверка одним другого будет неадекватной). Но в целом он чаще есть, чем его нет. Я их даже эпизодически прикручивал для своих нужд (например, в pldasm какие-то кусочки пихал для облегчения написания). Цитата(zltigo @ Apr 1 2008, 22:44)  А почему-бы и нет? Есть свои приятственные фичи в C++ компиляторах и для почти сишного кода. А как, например в смешанном коде без немерянных извращений работать с плюсовым кодом? Лично я в большинстве случаев так и поступаю. Это если говорить о сложившейся ситуации. И я тоже так делаю иногда, хотя и inline-функции, и объявление переменных по месту, включая счётчики в циклах for - есть в C99, просто до сих пор не все поддерживают. Да и в С99 есть не менее вкусная возможность инициализировать элементы структур/массивов по имени, в С++ этого нет. Так что... Где найдёшь, где потеряешь... А если говорить на момент "до того", когда язык С++ только сбивался и ещё и люди не привыкли пользоваться "С-совместимыми" расширениями С++, и "массы текстов" не набралось, то кто мешал "таки повыкидывать из С++ тяжкое наследие С, не приносящее ничего, кроме вреда"? По поводу смешанных проектов - никто не мешает весь С-текст держать в отдельных файлах, компилировать в С-режиме со всеми функциональными макросами, а потом линковать с С++ - программой, скомпилированной в С++ режиме. Ввели бы для условной компиляции что-то как-бы похожее, но интегрированное в язык, а не являющееся отдельным проходом. Как результат в условии компиляции можно было бы применять и enum-определённые константы и т.п. Кто мешал? И не было бы споров  Ну скучал бы я по старым добрым макросам  Цитата(_Pasha @ Apr 2 2008, 08:58)  А насчет пред/пост инкремента, например, действительно генератор граблей. Где? Как? Может, генератором граблей есть голова пишущего, не разобравшаяся в побочных эффектах и точках следования? Если так, то надо требовать изменения консти стандарта С таким образом, чтобы все переменные по умолчанию были volatile, так как от непонимания этого момента "глюков" ещё больше. Ну или просто компилировать свои программы с выключенной оптимизацией. Цитата(defunct @ Apr 2 2008, 11:58)  а повсеместно тыкать ++ / -- ни ни, я отдаю предпочтение p += 1 вместо ++;  Шаманим потихоньку? Стандарт С: Цитата 6.5.3.1 Prefix increment and decrement operators ... Semantics 2 The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. The expression ++E is equivalent to (E+=1). See the discussions of additive operators and compound assignment for information on constraints, types, side effects, and conversions and the effects of operations on pointers. 3 The prefix -- operator is analogous to the prefix ++ operator, except that the value of the operand is decremented. Цитата 6.5.16.2 Compound assignment Semantics 3 A compound assignment of the form E1 op= E2 differs from the simple assignment expression E1 = E1 op (E2) only in that the lvalue E1 is evaluated only once. ++E эквивалентно E+=1 всегдалюбое из них эквивалентно E = E + 1 в подавляющем большинстве случаев. Разница будет, например, для a[i] += 1; в случае, когда i объявлено как volatile, иначе выражения семантически эквивалентны.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 2 2008, 12:15
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(ReAl @ Apr 2 2008, 13:55)   Шаманим потихоньку? ++E эквивалентно E+=1 всегдаЭто я в курсе  Дело принципа и привычки, от ++ в глазах рябит. Как и написал выше ++/-- использую только для индексации и в условиях: while( zz--) { *p++ = xx; p[ idx++] = xx; } ... а когда стоит вопрос одинокого инкремента какой-то переменной или указателя то пользую p += 1;
|
|
|
|
|
Apr 2 2008, 12:40
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(defunct @ Apr 2 2008, 14:15)  Это я в курсе  Дело принципа и привычки, от ++ в глазах рябит. Фух, а то я уж, виноват, подумал, что это способ уменьшения размера глюкодрома по причине врождённой глюкавости операторов ++ --. Привычки - это нормально, ненормально когда их оправдывают высокими соображениями
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 2 2008, 16:40
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Позволю небольшой отрывок кода, извиняюсь что немного прерываю... доступ к флагам Код /**************************************************************************** Системные флаги ****************************************************************************/ #define System_Flags GPIOR0 enum { KEY_VALID = (1 << 0), NEED_FLASH = (1 << 1), SOUND_ENABLE = (1 << 2) };
void main (void){ if(System_Flags & KEY_VALID) System_Flags &= ~NEED_FLASH; if(System_Flags & NEED_FLASH) System_Flags &= ~SOUND_ENABLE; }; тот же код но с препроцессором Код #define System_Flags GPIOR0 #define KEY_VALID (1 << 0) #define NEED_FLASH (1 << 1) #define SOUND_ENABLE (1 << 2) void main (void){ if(System_Flags & KEY_VALID) System_Flags &= ~NEED_FLASH; if(System_Flags & NEED_FLASH) System_Flags &= ~SOUND_ENABLE; }; Даёт одинаковый код Код // 18 if(System_Flags & KEY_VALID) System_Flags &= ~NEED_FLASH; SBIC 0x1E, 0x00 CBI 0x1E, 0x01 // 19 if(System_Flags & NEED_FLASH) System_Flags &= ~SOUND_ENABLE; ??main_0: SBIC 0x1E, 0x01 CBI 0x1E, 0x02
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Apr 2 2008, 19:30
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(SasaVitebsk @ Apr 2 2008, 21:34)  ... совершенно очевидно, что компилятору по барабану написали ли вы формулу одним оператором или тремя. Качество сгенерированного кода не ухудшится Компиляторы умнеют, но тем не менее пока не умнее Вас и на подсказку вполне вероятно, ответят лучшим кодом. Цитата(singlskv @ Apr 2 2008, 22:19)  Более того, при написании 3мя операторами оно может и существенно улучшиться  если знаешь как правильно разбить эти 3 оператора на нужное количество строк... Вы знаете? Тогда пример в студию...... Цитата(_Pasha @ Apr 2 2008, 21:53)  Поэтому, когда мне закинут в уши мысль типа...  ну зачем-же гордится своей наивностью?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 2 2008, 20:31
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Apr 2 2008, 23:30)  Вы знаете? Тогда пример в студию...... Да пожалуйста, WinAvr20060421, на IAR тоже как-то проверял, чуть получше но тоже не блеск: Код #include <avr/io.h>
volatile unsigned char al=0xFF; volatile unsigned char ah=0xFF; volatile unsigned char Pb,Pc,Pd;
int main() { unsigned char pb,pc,pd;
unsigned char tmpl = al; unsigned char tmph = ah;
//------------ Вариант N1 ("правильный") pb = (tmph & 0b10000000) | ((tmph & 0b01110000) >> 1) | ((tmph & 0b00001100) >> 2); pc = ((tmph & 0b00000011) << 2) | ((tmpl & 0b11000000) >> 6); pd = tmpl <<2; //----- сохраняем результат Pb = pb; Pc = pc; Pd = pd;
tmpl = al; tmph = ah;
//------------ Вариант N2 ("неправильный :) ") pd = (tmpl << 2); pc = tmph & 0b01111100; pc >>= 1; pb = (tmph & 0b10000000); pb |= (pc & 0b00111000); pc &= 0b00000110; pc >>= 1; pb |= pc; pc = (tmph&0b00000011); pc <<= 2; pd = tmpl >> 6; pc |= pd; pd = tmpl << 2; //----- сохраняем результат Pb = pb; Pc = pc; Pd = pd;
//---------------------------
while (1);
} результат компиляции: Код pb = (tmph & 0b10000000) | ((tmph & 0b01110000) >> 1) | ((tmph & 0b00001100) >> 2); 6c: 24 2f mov r18, r20 6e: 33 27 eor r19, r19 70: c9 01 movw r24, r18 72: 80 77 andi r24, 0x70; 112 74: 90 70 andi r25, 0x00; 0 76: 95 95 asr r25 78: 87 95 ror r24 7a: 40 78 andi r20, 0x80; 128 7c: 48 2b or r20, r24 7e: c9 01 movw r24, r18 80: 8c 70 andi r24, 0x0C; 12 82: 90 70 andi r25, 0x00; 0 84: 95 95 asr r25 86: 87 95 ror r24 88: 95 95 asr r25 8a: 87 95 ror r24 8c: 48 2b or r20, r24 pc = ((tmph & 0b00000011) << 2) | ((tmpl & 0b11000000) >> 6); 8e: 23 70 andi r18, 0x03; 3 90: 30 70 andi r19, 0x00; 0 92: 22 0f add r18, r18 94: 33 1f adc r19, r19 96: 22 0f add r18, r18 98: 33 1f adc r19, r19 9a: 85 2f mov r24, r21 9c: 99 27 eor r25, r25 9e: 36 e0 ldi r19, 0x06; 6 a0: 96 95 lsr r25 a2: 87 95 ror r24 a4: 3a 95 dec r19 a6: e1 f7 brne .-8 ; 0xa0 <main+0x44> a8: 28 2b or r18, r24 pd = tmpl <<2; aa: 55 0f add r21, r21 ac: 55 0f add r21, r21 Код pd = (tmpl << 2); pc = tmph & 0b01111100; c2: 24 2f mov r18, r20 c4: 2c 77 andi r18, 0x7C; 124 pc >>= 1; c6: 26 95 lsr r18 pb = (tmph & 0b10000000); c8: 94 2f mov r25, r20 ca: 90 78 andi r25, 0x80; 128 pb |= (pc & 0b00111000); cc: 82 2f mov r24, r18 ce: 88 73 andi r24, 0x38; 56 d0: 98 2b or r25, r24 pc &= 0b00000110; d2: 26 70 andi r18, 0x06; 6 pc >>= 1; d4: 26 95 lsr r18 pb |= pc; d6: 92 2b or r25, r18 pc = (tmph&0b00000011); d8: 24 2f mov r18, r20 da: 23 70 andi r18, 0x03; 3 pc <<= 2; dc: 22 0f add r18, r18 de: 22 0f add r18, r18 pd = tmpl >> 6; e0: 85 2f mov r24, r21 e2: 82 95 swap r24 e4: 86 95 lsr r24 e6: 86 95 lsr r24 e8: 83 70 andi r24, 0x03; 3 pc |= pd; ea: 28 2b or r18, r24 pd = tmpl << 2; ec: 55 0f add r21, r21 ee: 55 0f add r21, r21 ИТОГО: "Правильный" 21 слов 58 тактов "Неправильный" 17 слов 23 такта Выводы делаем сами
|
|
|
|
|
Apr 2 2008, 21:22
|

Частый гость
 
Группа: Свой
Сообщений: 160
Регистрация: 17-03-08
Из: Мурманская
Пользователь №: 35 989

|
На СИ, правильно когда по-больше зелени (#define), а на C++, а тем более шарпе, - когда этого по-меньше. Шучу. Важно чтобы программа работала, менее важно - как она написана. Если расчитывать что кому-то придется в этом коде разбираться, то желательно писать коментарии. Даже самому приходится иногда разбирая старый код вспоминать что же там имелось ввиду. Мне нравится стиль Microsoft, лучше трудно придумать.
--------------------
Демократия - это когда считается, что два дурака лучше одного умного Суверенная демократия - это когда считается, что один дурак лучше двух дураков
|
|
|
|
|
Apr 2 2008, 21:51
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Apr 2 2008, 23:31)  Да пожалуйста, WinAvr20060421, на IAR тоже как-то проверял, чуть получше но тоже не блеск: Ну и где обещанная экономия от Цитата ...правильно разбить эти 3 оператора на нужное количество строк... Налицо ДВА РАЗНЫХ АЛГОРИТМА, а не описание одного и того-же "разным количеством строк". Кроме того, посмею предположить, что под нормально оптимизирующим компилятором разница будет в пару команд максимум. Цитата Выводы делаем сами Сделал  Цитата(AlexKLm @ Apr 3 2008, 00:22)  Мне нравится стиль Microsoft, лучше трудно придумать. Трудно придумать стиль в котором больше жертв принесено стилю ради собственно абсолютно формального стиля.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 2 2008, 21:55
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Apr 3 2008, 01:47)  Налицо ДВА РАЗНЫХ АЛГОРИТМА, с ОДИНАКОВЫМ результатом, и принципиально не различающимся методом вычислений, + если Вы не обратили внимание, во втором варианте операции на одну больше  Цитата Кроме того, посмею предположить, что под нормально оптимизирующим компилятором разница будет в пару команд максимум. покажите результат компиляции...
|
|
|
|
|
Apr 2 2008, 22:08
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Apr 3 2008, 00:55)  покажите результат компиляции... А самому? Думаете поленюсь copy-paste и убрать отрыжки древних ассемблеров не имеющих препроцессоров? Ладно: Код // 19 void m1(void) m1: // 20 { // 21 unsigned char pb,pc,pd; // 22 // 23 unsigned char tmpl = al; LDI R30, LOW(al) LDI R31, (al) >> 8 LD R19, Z // 24 unsigned char tmph = ah; LDD R16, Z+1 // 25 // 26 //------------ Вариант N1 ("правильный") // 27 pb = ( tmph & 0x80 )|( (tmph & 0x70) >> 1 )|( (tmph & 0xC0) >> 2 ); // 28 pc = ((tmph & 0x03) << 2 )|( (tmpl & 0xC0) >> 6 ); // 29 pd = tmpl <<2; // 30 // 31 //----- сохраняем результат // 32 Pb = pb; MOV R18, R16 ANDI R18, 0x80 MOV R17, R16 ANDI R17, 0x70 ASR R17 OR R18, R17 MOV R17, R16 ANDI R17, 0xC0 LSR R17 LSR R17 OR R18, R17 STD Z+2, R18 // 33 Pc = pc; ANDI R16, 0x03 LSL R16 LSL R16 LDI R17, 4 MUL R19, R17 OR R16, R1 STD Z+3, R16 // 34 Pd = pd; LSL R19 LSL R19 STD Z+4, R19 // 35 // 36 } RET
// 38 void m2(void) m2: // 39 { // 40 // 41 unsigned char pb,pc,pd; // 42 // 43 unsigned char tmpl = al; LDI R30, LOW(al) LDI R31, (al) >> 8 LD R20, Z // 44 unsigned char tmph = ah; LDD R18, Z+1 // 45 // 46 //------------ Вариант N2 ("неправильный :) ") // 47 pd = (tmpl << 2); // 48 // 49 pc = tmph & 0x7C; // 50 pc >>= 1; MOV R17, R18 ANDI R17, 0x7C LSR R17 // 51 // 52 pb = (tmph & 0x80); // 53 pb |= (pc & 0x38); // 54 pc &= 0x06; // 55 pc >>= 1; // 56 pb |= pc; // 57 pc = tmph & 0x03; // 58 pc <<= 2; // 59 pd = tmpl >> 6; // 60 pc |= pd; // 61 pd = tmpl << 2; // 62 //----- сохраняем результат // 63 Pb = pb; MOV R19, R18 ANDI R19, 0x80 MOV R16, R17 ANDI R16, 0x38 OR R19, R16 ANDI R17, 0x06 LSR R17 OR R19, R17 STD Z+2, R19 // 64 Pc = pc; ANDI R18, 0x03 LSL R18 LSL R18 LDI R16, 4 MUL R20, R16 OR R18, R1 STD Z+3, R18 // 65 Pd = pd; LSL R20 LSL R20 STD Z+4, R20 // 66 } RET P.S. Получилось, что все ухищрения яйца выеденного не стоят....
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 2 2008, 22:32
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(singlskv @ Apr 2 2008, 23:55)  с ОДИНАКОВЫМ результатом, и принципиально не различающимся методом вычислений, Но тем не менее разных алгоритма :-) Кстати, если переписать это так, как привычно мне  - сначала сдвиги, потом маскирования (так как сдвиги С часто компилируются в ассемблерные сдвиги с последующим маскированием, маскирования, разделённые сдвигом, часто остаются, хотя они и ихбыточные, а вот два маскирования подряд компиляторы как правило объединяют  ), да и мне лично проще анализировать "сначала сдвиг, потом маскирование" Код __asm__ volatile ("nop" ::); // так удобнее искать потом границы фрагментов
tmpl = al; tmph = ah;
pb = (tmph & 0b10000000) | ((tmph >> 1) & 0b00111000) | ((tmph >> 2) & 0b00000011); pc = ((tmph << 2) & 0b00001100) | ((tmpl >> 6) & 0b00000011); pd = tmpl <<2; //----- Pb = pb; Pc = pc; Pd = pd; __asm__ volatile ("nop" ::); то особой разницы-то и под gcc не видно... Код /* #APP */ nop /* #NOAPP */ lds r19,al lds r25,ah mov r18,r25 lsr r18 andi r18,lo8(56) mov r24,r25 lsr r24 lsr r24 andi r24,lo8(3) or r18,r24 mov r24,r25 andi r24,lo8(-128) or r18,r24 lsl r25 lsl r25 andi r25,lo8(12) mov r24,r19 swap r24 lsr r24 lsr r24 andi r24,lo8(3) or r25,r24 lsl r19 lsl r19 sts Pb,r18 sts Pc,r25 sts Pd,r19 /* #APP */ nop /* #NOAPP */ lds r20,al lds r25,ah mov r24,r25 andi r24,lo8(124) lsr r24 mov r19,r24 andi r19,lo8(56) mov r18,r25 andi r18,lo8(-128) or r19,r18 andi r24,lo8(6) lsr r24 or r19,r24 andi r25,lo8(3) lsl r25 lsl r25 mov r24,r20 swap r24 lsr r24 lsr r24 andi r24,lo8(3) or r25,r24 sts Pb,r19 sts Pc,r25 lsl r20 lsl r20 sts Pd,r20 .L2: rjmp .L2 Цитата(zltigo @ Apr 2 2008, 23:51)  Трудно придумать стиль в котором больше жертв принесено стилю ради собственно абсолютно формального стиля. +1 У меня мозги в трубочку сворачиваются и через уши вылазят, когда я вижу идентификаторы в стиле ВЗБЗД взбздНуть; Их трудно произнести и, как следствие, ими трудно мыслить. Зато вылет за правый край экрана даже при отступах по 2 символа (о ужас дельфийский) гарантирован даже на операторах средней сложности. Итого народ пишет исключительно простые, но софт от этого ни компактнее, ни лучше не становится. Как, впрочем, не становится лучше и обычный текст, не содержащий совершенно сложноподчинённых предложений, а состоящий из одних простых ("зато нет глюкодрома с запятыми"  ).
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 2 2008, 22:37
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Apr 3 2008, 02:08)  и убрать отрыжки древних ассемблеров не имеющих препроцессоров? это не отрыжки, это удобство для данной конкретной задачки, по битикам видно что куда попадает, но это просто специфика... Кстати Вы вот так и ошиблись при переводе из двоичного представления в 16x вот так: (tmph & 0b10000000)......(tmph & 0b01110000).......(tmph & 0b00001100 ) сразу же видно что взяли нужные битики, а вот так нифига не видно: ( tmph & 0x80 )........(tmph & 0x70)..........(tmph & 0xC0 ) Цитата Я же говорю, пробовал, раньше код был намного хуже. Какая версия ? С таким выходом - убедили!
|
|
|
|
|
Apr 2 2008, 22:46
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(singlskv @ Apr 3 2008, 00:37)  Я же говорю, пробовал, раньше код был намного хуже. Какая версия ? Мой вариант - 20071221, но и на 20060421 полный паритет между вариантами "мой самый правильный"  и "неправильный" Код /* #APP */ nop /* #NOAPP */ lds r21,al lds r20,ah mov r25,r20 andi r25,lo8(-128) mov r24,r20 lsr r24 andi r24,lo8(56) or r25,r24 mov r24,r20 lsr r24 lsr r24 andi r24,lo8(3) or r25,r24 lsl r20 lsl r20 andi r20,lo8(12) mov r24,r21 swap r24 lsr r24 lsr r24 andi r24,0x3 or r20,r24 lsl r21 lsl r21 sts Pb,r25 sts Pc,r20 sts Pd,r21 /* #APP */ nop /* #NOAPP */ lds r21,al lds r20,ah mov r18,r20 andi r18,lo8(124) lsr r18 mov r25,r20 andi r25,lo8(-128) mov r24,r18 andi r24,lo8(56) or r25,r24 andi r18,lo8(6) lsr r18 or r25,r18 mov r18,r20 andi r18,lo8(3) lsl r18 lsl r18 mov r24,r21 swap r24 lsr r24 lsr r24 andi r24,0x3 or r18,r24 lsl r21 lsl r21 sts Pb,r25 sts Pc,r18 sts Pd,r21 .L2: rjmp .L2 У меня на компе и 20060421 до сих пор стоит, на всякий случай.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 2 2008, 23:25
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(ReAl @ Apr 3 2008, 02:32)  Кстати, если переписать это так, как привычно мне  - сначала сдвиги, потом маскирования (так как сдвиги С часто компилируются в ассемблерные сдвиги с последующим маскированием, маскирования, разделённые сдвигом, часто остаются, хотя они и ихбыточные, а вот два маскирования подряд компиляторы как правило объединяют  ), да и мне лично проще анализировать "сначала сдвиг, потом маскирование" Так собственно мы и сделали одно и тоже но разными средствами Цитата(ReAl @ Apr 3 2008, 02:46)  Мой вариант - 20071221, но и на 20060421 полный паритет между вариантами "мой самый правильный"  и "неправильный" Мне просто почему-то удобнее мыслить сначала маскированием а потом сдвигами, а 20060421 ну никак не хотел ко мне привыкать  Цитата(ReAl @ Apr 3 2008, 02:46)  У меня на компе и 20060421 до сих пор стоит, на всякий случай. OFF: Кстати, может быть у Вас есть ответ на вот этот вопрос: http://electronix.ru/forum/index.php?showtopic=26519Никто так ничего толком и не ответил, пару раз неприятно натыкался, кроме как ручной тасовкой команд решения не знаю...
|
|
|
|
|
Apr 2 2008, 23:45
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(singlskv @ Apr 3 2008, 00:55)  Так собственно мы и сделали одно и тоже но разными средствами Так я и не говорю, что сделано что-то совсем другое (в отличие от варианта в 10 строк), просто неболшое переупорядочивание операций под мою голову  Цитата(singlskv @ Apr 3 2008, 00:55)  Мне просто почему-то удобнее мыслить сначала маскированием а потом сдвигами, Если выделяется какое-то битовое поле в "целочисленную переменную", то "сначала сдвиг" показывает, где поле начиналось, а "потом маскирование" это просто число единичек справа, равное длине поля, т.е. Код fld = (var >> field_start) & ((1 << field_len) - 1); А если сначала маскирование, то выражение становится запутаннее. Поскольку мне чаще приходилось именно получать нужные поля начиная с 0-ого бита переменной, в которую они заносились - мне привычнее такой вариант. Кстати, господа хорошие, что-то мне кажется, что этот вариант: Код unsigned char tmph = ah; unsigned int tmp = (tmph<<8) | al; tmp <<= 2; pb = tmph & 0b10000000; tmph >>= 1; pb |= tmph & 0b00111000; tmph >>= 1; pb |= tmph & 0b00000011; //----- Pb = pb; Pc = (tmp>>8) & 0x0F; Pd = tmp; Самый понятный с точки зрения "а что, собственно, делается". И даже несмотря на традиционно плохонькую реализацию в gcc склеивания слова из двух байтов и выделения старшего байта слова (после оптимизатора остаются рудименты "integer promotion") - он находится "где-то там же" по длине. Код lds r20,ah lds r24,al mov r18,r20; во аж сколько заняло ldi r19,lo8(0); unsigned int tmp = (tmph<<8) | al; mov r19,r18; clr r18; ldi r25,lo8(0); or r18,r24; or r19,r25; lsl r18 rol r19 lsl r18 rol r19 mov r24,r20 lsr r24 mov r25,r24 andi r25,lo8(56) andi r20,lo8(-128) or r25,r20 lsr r24 andi r24,lo8(3) or r25,r24 sts Pb,r25 mov r24,r19; а это недочищенный хвосты clr r25; (tmp>>8) & 0x0F; andi r24,lo8(15) sts Pc,r24 sts Pd,r18 Если бы оптимизатор был тут немного умнее, или если применить макрос-вставку Код #define HILOTO16(hi, lo) ({ \ unsigned int __result; \ __asm__ ( " mov %B0,%1 \n" : "=r" (__result) : "r" (hi), "0" (lo) ); \ __result; }) ... ... tmph = ah; unsigned int tmp = HILOTO16(tmph, al); tmp <<= 2; pb = tmph & 0b10000000; tmph >>= 1; pb |= tmph & 0b00111000; tmph >>= 1; pb |= tmph & 0b00000011; //----- Pb = pb; Pc = (tmp>>8) & 0x0F; Pd = tmp; То по сравнению с "неправильным", казалось бы "уоптимизированным вусмерть" и практически непонятным вариантом выходит гораздо короче: Код lds r25,ah lds r18,al ; /* #APP */ mov r19,r25; это то, что вышло из макроса HILOTO16(), /* #NOAPP */; правильный оптимизатор должен был бы сделать так же. lsl r18 rol r19 lsl r18 rol r19 mov r24,r25 lsr r24 mov r20,r24 andi r20,lo8(56) andi r25,lo8(-128) or r20,r25 lsr r24 andi r24,lo8(3) or r20,r24 sts Pb,r20 mov r24,r19; это уж ладно clr r25; andi r24,lo8(15) sts Pc,r24 sts Pd,r18 Цитата(singlskv @ Apr 3 2008, 01:25)  OFF: Кстати, может быть у Вас есть ответ на вот этот вопрос: http://electronix.ru/forum/index.php?showtopic=26519Никто так ничего толком и не ответил, пару раз неприятно натыкался, кроме как ручной тасовкой команд решения не знаю... Ответ таков - если это жутко критичное по скорости место - вписать ассемблерную вставку и забыть. Иначе - забить. Ну хуже оптимизаторы, чем они в принципе могут быть, хуже. Если постоянно копаться в выдаче компилятора и страдать от недооптимизации - то лучше перейти на асм. Кстати, в большинстве случаев -Os для AVR даёт лучше код, чем -O2 :-)
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 3 2008, 05:53
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Apr 3 2008, 01:37)  это не отрыжки, это удобство для данной конкретной задачки, по битикам видно что куда попадает, но это просто специфика... Да ничего не видно, при "видно" не ошибся-бы,даже в 2 часа ночи... А тут даже на 8bit глазоломка, а уж на 32  Цитата сразу же видно что взяли нужные битики, Более-менее видно когда такое написано,хоть на ASM, хоть на C, как минимум так: Код ( tmph & BIT7 )........(tmph & (BIT6|BIT5|BIT4)).......... а вобще надо давать осмысленные имена Код ( tmph & B_SIGN )........(tmph & M_LEVEL).......... Цитата Я же говорю, пробовал, раньше код был намного хуже. Какая версия ? IAR 5.10, но, полагаю, и на 4.x будет тот-же результат.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 3 2008, 08:28
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(SasaVitebsk @ Apr 3 2008, 09:23)  Вот я и говорю, что результат практически тот же при оптимизации, а при отладке неудобно большие громоздкие формулы (в приведенных примерах вполне нормальные). Поэтому здоровую формулу, с возможностью неоднозначного вычисления (точнее требующую специального разбора порядка вычисления), лучше разбить на пару однозначных. Компилятору всё равно, а человеку удобнее. Я бы сказал, что как раз этому критерию приведенный пример не отвечает абсолютно. "неправильный" вариант гораздо труднее для понимания, и чем первый "правильный", и чем мой с 16-битной переменной. Микс из элементарных операций с разными переменными, который нужно много раз прочесть туда-назад, чтобы понять в чём дело. Он выглядит скорее как "а вот я умнее компилятора и напишу на С, но как бы на асме (всё равно не имея всех асмовых возможностей, кстати) и оно будет компактнее и работать быстрее", а не как "в таком виде оно понятнее человеку".
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 7 2008, 10:40
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(zltigo @ Apr 2 2008, 22:30)  Компиляторы умнеют, но тем не менее пока не умнее Вас и на подсказку вполне вероятно, ответят лучшим кодом. К примеру с чем связано столько заморочек в ВИН АВР? Макрос доступа к битам порта средствами ВИН АВР, например sbi(PORTB, 5); Подняв несколька файлов и сделав соответствующие подстановки получаем следующее ( адрес порта Б к примеру 0x08) Код ((*(volatile uint8_t *)(((uint16_t) &((*(volatile uint8_t *)((0x08) + 0x20)))) )) |=(1 << (5))) средствами ИАР это дело обстоит намного проще и находится в одном файле avr_macros.h Код /* Set BIT in ADDRESS */ #define SETBIT(ADDRESS,BIT) ((ADDRESS) |= (1<<(BIT)))
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Apr 7 2008, 10:58
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата средствами ИАР это дело обстоит намного проще А как насчёт то же применить в WinAVR? Неужели этот макрос там не будет работать? Вы хоть попробовать-то пытались?
--------------------
aka Vit
|
|
|
|
|
Apr 7 2008, 11:07
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(sensor_ua @ Apr 7 2008, 13:58)  А как насчёт то же применить в WinAVR? Неужели этот макрос там не будет работать? Вы хоть попробовать-то пытались? Да, я немного не про то. Конечно он будет работать. Это и такому дураку как я понятно  Попробуйте в ИАР вот так и объясните почему, а то мне дураку не ясно Допустим нужно установить в единицу четвёртый бит порта ну пускай Б Настроим его как выход, назовём его HELS Код #define HELSp B #define HELSb 4 CLRDDR(HELS);// направление SETPORT(HELS);// бит 4 порта Б единичка
Сообщение отредактировал sKWO - Apr 7 2008, 11:41
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Apr 7 2008, 12:51
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Не очень понял, что Вы хотите, но на телесистемах на днях обсуждался вариант доступа только по имени. Код typedef volatile uint8_t * port_t;
typedef struct Port_Bit{ port_t Port; unsigned char Bit; }Port_Bit;
void CLRDDR(const Port_Bit * pb){ *(pb->Port-1) &= ~(1 << pb->Bit); } void SETPORT(const Port_Bit * pb){ *(pb->Port) |= 1 << pb->Bit; }
Port_Bit dHELS={&PORTB, 4}; const Port_Bit * HELS = &dHELS;
--------------------
aka Vit
|
|
|
|
|
Apr 7 2008, 19:43
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(sKWO @ Apr 7 2008, 13:40)  К примеру с чем связано столько заморочек в ВИН АВР? Макрос доступа к битам порта средствами ВИН АВР, например sbi(PORTB, 5); Подняв несколька файлов и сделав соответствующие подстановки получаем следующее ( адрес порта Б к примеру 0x08) Код ((*(volatile uint8_t *)(((uint16_t) &((*(volatile uint8_t *)((0x08) + 0x20)))) )) |=(1 << (5))) средствами ИАР это дело обстоит намного проще и находится в одном файле avr_macros.h Код /* Set BIT in ADDRESS */ #define SETBIT(ADDRESS,BIT) ((ADDRESS) |= (1<<(BIT))) Средствами WinAVR это "всё" тоже было одной практически такой же строкой Код #define sbi(port, bit) (port) |= (1 << (bit)) Зачем её было раскручивать? Какая разница что там, если оно всё равно компилируется в одну такую же команду ассемблера, что и у IAR ? Ведь для SETBIT(PORTB,5) вы же у IAR не раскручивали, что такое PORTB и не сравнивали с WinAVR? А он выглядит так WinAVR: Код #define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr)) #define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + 0x20) ... #define PORTB _SFR_IO8(0x18) Кстати, что-то Ваш вариант раскрутки sbi(port,bit) длинноват, выходит короче Код ( *(volatile uint8_t *)((0x08) + 0x20) ) |=(1 << (5)) IAR: Код #define __BYTEBITS(_NAME,_A,_B,_C,_D,_E,_F,_G,_H) \ unsigned char _NAME ## _ ## _A:1, \ _NAME ## _ ## _B:1, \ _NAME ## _ ## _C:1, \ _NAME ## _ ## _D:1, \ _NAME ## _ ## _E:1, \ _NAME ## _ ## _F:1, \ _NAME ## _ ## _G:1, \ _NAME ## _ ## _H:1;
#define SFR_B_BITS(_NAME, _ADDR, _A,_B,_C,_D,_E,_F,_G,_H) \ __io union { \ unsigned char _NAME; /* The sfrb as 1 byte */ \ struct { /* The sfrb as 8 bits */ \ __BYTEBITS(_NAME, _A,_B,_C,_D,_E,_F,_G,_H) \ }; \ } @ _ADDR;
#define SFR_B(_NAME, _ADDR) SFR_B_BITS(_NAME, _ADDR, \ Bit0,Bit1,Bit2,Bit3,Bit4,Bit5,Bit6,Bit7) ...
SFR_B(PORTB, 0x18) Так что у IAR просто наворочено в другом месте, до которого просто Вы не добрались :-) Как лучше - тяжело сказать. Вариант IAR позволяет написать Код SPMCR.SPMIE = 1; вместо Код SPMCR |= (1 << SPMIE); или SPMCR |= _BV(SPMIE); зато не позволяет сделать то, что позволяет avr-gcc (к чему это приводит - см, например, http://electronix.ru/forum/index.php?s=&am...st&p=377042 ) Код #if defined(SPMCSR) # define SPM_CONTROL_REG SPMCSR #elif defined(SPMCR) # define SPM_CONTROL_REG SPMCR #else # error "SPM control register not defined" #endif
...
SPM_CONTROL_REG |= (1 << SPMIE); Таким образом для всех кристаллов, у которых есть либо SPMCR либо SPMCSR - можно обойтись несколькими строками кода и получить исходник, компилирующийся для всего. У IAR для этого придётся персонально проверять типы процесоров через Код #if defined(__AT90Mega88__) || defined(__AT90Mega168__) || ... А всё потому, что PORTB да SPMCR у avr-gcc это макросы препроцессора, а у IAR - переменные-вложенные агрегаты, прибитые гвозядми к адресам, поэтому их наличие или отсутствие препроцессор не видит и нельзя сделать условную компиляцию просто проверив наличие имени регистра. Цитата(sKWO @ Apr 7 2008, 14:07)  Допустим нужно установить в единицу четвёртый бит порта ну пускай Б Настроим его как выход, назовём его HELS Код #define HELSp B #define HELSb 4 CLRDDR(HELS);// направление SETPORT(HELS);// бит 4 порта Б единичка Это вообще уже лет 10 не так делается. Код #define LED1 B,0,L /* светодиод анодом на питание, зажигаем низким уровнем - L */ #define LED2 D,1,H /* светодиод катодом на землю, зажигаем высоким уровнем */ #define KEY1 C,2,L /* кнопка на землю, при нажатии низкий уровень */ #define KEY2 A,3,H /* кнопка на питание, при нажатии высокий уровень */ ... // теперь не глядя на полярности сигналов пишем ON, чтобы включить, а включается // нулём или единичкой - макрос разбирается DRIVER(LED1,OUT); DRIVER(LED2,OUT); DRIVER(KEY1,IN); DRIVER(KEY1,PULLUP); // к примеру тут обходимся внутренней подтяжкой DRIVER(KEY2,IN); DRIVER(KEY2,HIZ); // а тут внешняя подтяжка на землю ... if( ACTIVE(KEY1) ) { ON(LED1); OFF(LED2); }
if( ACTIVE(KEY2) ) OFF(LED1);
if( flag) ) CPL(LED2); // проинвертировали ногу Называется "макросы Аскольда Волкова", модифицировалось уже под разные процессоры и компиляторы всеми кому не лень. Вот мой вариант:
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 8 2008, 11:00
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(ReAl @ Apr 7 2008, 22:43)  Называется "макросы Аскольда Волкова", модифицировалось уже под разные процессоры и компиляторы всеми кому не лень. C макросами ядерного физика Аскольда Волкова давно знаком, удобная вещь, когда-то на Телесисах он его представлял, собственно как и его модификацию которую выложил Сергей Борщ. Конечно же их использую. Цитата(ReAl @ Apr 7 2008, 22:43)  А всё потому, что PORTB да SPMCR у avr-gcc это макросы препроцессора, а у IAR - переменные-вложенные агрегаты, прибитые гвозядми к адресам, поэтому их наличие или отсутствие препроцессор не видит и нельзя сделать условную компиляцию просто проверив наличие имени регистра. За это большое спасибо! Цитата(ReAl @ Apr 7 2008, 22:43)  длинноват, выходит короче Код ( *(volatile uint8_t *)((0x08) + 0x20) ) |=(1 << (5)) Код в файле sfr_def.h находим #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) дальше #define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr)) дальше #define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr)) #define _SFR_ADDR(sfr) _SFR_MEM_ADDR(sfr) #define _SFR_MEM_ADDR(sfr) ((uint16_t) &(sfr)) получаем #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) подставляем #define sbi(sfr, bit) ( (*(volatile uint8_t *)( ((uint16_t) &(sfr)) )) |= _BV(bit)) смотрим в pgmspace.h _BV #define _BV(bit) (1 << (bit)) видим #define sbi(sfr, bit) ((*(volatile uint8_ t *)(((uint16_t) &(sfr)) )) |= (1 << (bit))) всё хорошо получается или чёта провтыкал? имеем следующее ((*(volatile uint8_t *)(((uint16_t) &(PORTB )) )) |= (1 << (5))) ну и остаётся за малым подставить знач порта допустим #define PORTB _SFR_IO8(0x08) находим _SFR_IO8 в файле sfrdefs.h #define _SFR_IO8(io_addr) _MMIO_BYTE ((io_addr) + 0x20) соответственно _SFR_IO8(0x08) есть_MMIO_BYTE((0x08) + 0x20) а _MMIO_BYTE((0x08) + 0x20) есть (*(volatile uint8_t *)((0x08) + 0x20)) отсюда и получается ((*(volatile uint8_t *)(((uint16_t) &((*(volatile uint8_t *)((0x08) + 0x20)))) )) |=(1 << (5))) Выходит разные версии компилят , наверное
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|