|
|
  |
Стиль программирования на Си, описание функции |
|
|
|
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 смысла нет).
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|