|
|
  |
Вопрос к знатокам С. |
|
|
|
Nov 11 2008, 20:02
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
гм... я и не говорил, что пустой if - это норма... я как раз придерживаюсь противоположного мнения... а вот присваивание временной переменной с моей точки зрения - вполне нормальная практика, логичная и не нарушающая никакие стандартны-нормы-правила. volatile тут совсем ни при чем - этот модификатор никто не отменял и его значение (и назначение) не оспаривается.
на счет "специально заведенных переменных"... на сколько я понимаю, при определенном напряжении сил можно очень сложные выражения (например, нечто типа БПФ) уместить в единственном операторе, избежав "лишних" переменных (обычно они называются локальными)... и, хотя с точки зрения результата это будет совершенно верное "выражение", назвать его удобочитаемым будет можно вряд ли. скорее всего и по объему результирующего кода результат не будет отличаться от "развернутого" варианта...
практика заведения "лишних" переменных лишь для того, чтобы алгоритм вырисовывался четко и ясно с моей точки зрения вполне разумна и оправдана. а компилятор пускай соптимизирует явную избыточность - на то он и компилятор. кстати, весьма оправдан и подход, когда даже небольшие кусочки алгоритма оформляются отдельными функциями - лишь бы наглядность кода была на должном уровне.
можно сколько угодно рассуждать о том, что компилятор "должен сделать", если встретит просто упоминание переменной, но ведь если записать чуть иначе - пропадет сам предмет спора, ибо поведение компилятора станет очевидно на 100%.
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Nov 11 2008, 22:04
|

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

|
Если Вам приятно в таком духе - продолжайте, утрируйте, доходите до нелепиц и спорьте с ними - но без меня. Я вижу разницу между промежуточными переменными для разбивки сложных выражений на более простые и лишними переменными, в которые пишется для того, чтобы никогда из них не читать и этой записью ничего в окружении программы не менять (так как сама эта лишняя переменная - и не SFR и никогда никем не читается). Если бы эта запись была необходимым или достаточным условием для чтения из переменной в правой части независимо от её volatile-ности, то в этом был бы смысл. На мой взгляд в такой записи смысла приблизительно столько же, сколько в комментарии Код for( i = 0; i < 5; ++i /* инкрементируем счётчик цикла */) { } (хотя для малознакомого с С новичка этот комментарий и повышает читаемость), так как она всего лишь косвенно, через запсиь в другую переменную, говорит "а мы эту переменную прочитали!" для того, кто этого сам не видит. Всего лишь.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 14 2008, 11:31
|

nofb
  
Группа: Свой
Сообщений: 430
Регистрация: 18-05-06
Из: Москва, Зеленоград
Пользователь №: 17 218

|
 Обсуждение напоминает обсуждение кода типа Код unsigned char a if (a == a) {a=a;} "Индийский код..." Чем не устраивает вариант с просмотром дизассемблерного варианта полученного кода? Все сразу встанет на свои места - что лучше, а что хуже..
--------------------
Это не то что вы подумали ...
|
|
|
|
|
Nov 17 2008, 15:59
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
хочу для универсализма сделать версию функции printf() для вывода строки на 7-сегментный индикатор, при этом реализация получается примерно такая: Код void printf_7led(char *format, ... ){ char st[20]; sprintf(&st, format, ???); // вот тут трабла - обозначена вопросами // далее мой код, обрабатывающий st[] } трабла такая: как передать "хвост" аргументов, полученных на входе в printf_7led непосредственно в вызываемый sprintf? P.S. Работаю с WinAVR (GCC)
Сообщение отредактировал ARV - Nov 17 2008, 16:01
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Nov 17 2008, 16:24
|

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

|
Код void printf_7led(char *format, ... ){ va_list args; va_start(args, format); char st[20]; vsprintfs(st, format, args); va_end(args); Но это не совсем правильный с точки зрения avr_libc метод. правильно будет примерно так: Код int putchar_7led(int symbol, FILE *stream) { ... } FILE Display;
void main() { Display = FDEV_SETUP_STREAM(putchar_7led, NULL, _FDEV_SETUP_WRITE);
fprintf(&Display, "%s", "Hello"); for(;;); }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 11 2008, 08:56
|

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

|
Цитата(ARV @ Nov 17 2008, 19:25)  мне кажется, это хоть и красивый метод, но для 6-символьного 7-сегментного дисплея наверное слишком избыточный... просто строчку вывел - сразу понятно, что предыдущая затерлась... а при посимвольном выводе надо как-то так же красиво и логично отслеживать момент, когда строка кончилась... не находите? Ну избыточный он не этим - на шести символах просто толком негде разгуляться форматными строками с ширинами полей и т.п. А что касается "отслеживать момент" - да на раз, було бы желание покуражиться. Можно заставить по '\n' очищать строку - причём: - либо сразу по нему, тогда выводить строки вида "\nHELLO", что будет приводить к очистке и выводу, последующий вывод допишет в конец - либо по нему запоминать, что строка была завершена и уже последующий вывод очистит и начнёт с начала строки, тогда выводить (&Display, "Err %02X\n", err_code); Во втором случае в putchar_7led заводится статический флаг, который запоминает прохождение '\n' Код int putchar_7led(int symbol, FILE *stream) { static bool newline = true; if( symbol == '\n') { newline = true; } else { if( newline ) { // прочистить пробелами весь индикатор и поставить указатель символа // на начало буфера динамической индикации } newline = false; // вывести символ в текущую позицию } }
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Dec 12 2008, 07:09
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(ReAl @ Dec 11 2008, 11:56)  Ну избыточный он не этим - на шести символах просто толком негде разгуляться форматными строками с ширинами полей и т.п. А что касается "отслеживать момент" - да на раз, було бы желание покуражиться. как раз желания куражиться и не было. я поступил по первому совету - сделал оберточные функции для sprintf с преобразованием нормальных символов в семисегментные и весьма доволен результатом. на верхнем уровне и для семисегментника пишу printf_7led("%.2u", var) - и все выводится  а когда надо, то и так работает printf_7led("stop"). жаль, не все буквы в семисегментные варианты преобразуются  особенно кириллица - слишкам многа букафф
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Dec 25 2008, 00:06
|

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

|
Цитата(ARV @ Nov 11 2008, 22:02)  практика заведения "лишних" переменных лишь для того, чтобы алгоритм вырисовывался четко и ясно с моей точки зрения вполне разумна и оправдана. а компилятор пускай соптимизирует явную избыточность - на то он и компилятор. кстати, весьма оправдан и подход, когда даже небольшие кусочки алгоритма оформляются отдельными функциями - лишь бы наглядность кода была на должном уровне. Для того чтобы алгоритм вырисовывался "четко и ясно", на мой взгляд больше подходит другая практика. Во-первых избегать появления дурного кода - т.е. сводить в минимуму потребность в таких вот "var;" и лишних переменных. С какого бодуна драйвер решил вдруг опустошить содержимое буферов? Ведь можно построить драйвер так, что тупое опустошение не понадобится вовсе! Или почему SPSR надо обязательно читать в никуда? Можно же хотя бы в целях статистики хранить последнее значение SPSR: Код ISR() { ... spiContext.LastSpsrVal = SPSR; } производительности-то оно не сожрет. во-вторых - применять практику самодокументируемого кода - завести однозначно понятные макросы: Код #define access( x ) // обращение к X #define ignore( x ) // игнорировать x ... Встретив в коде Код access( SPSR ); Даже те "кто в танке" сразу поймут, что делается с SPSR. А столкнувшись с "финтом" компилятора - достаточно поменять только тело макроса...
|
|
|
|
|
Dec 25 2008, 08:21
|

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

|
Цитата(defunct @ Dec 25 2008, 03:06)  С какого бодуна драйвер решил вдруг опустошить содержимое буферов? Ведь можно построить драйвер так, что тупое опустошение не понадобится вовсе! Научите  у LPC2000 за тем-же SPI есть FIFO которое - не отключается - нет возможности сбросить его Как сделать запись по SPI так, что-бы когда-нибудь при чтении можно было прочтать SPI, а не содержимое забитого при записи FIFO. Цитата Или почему SPSR надо обязательно читать в никуда? Можно же хотя бы в целях статистики хранить последнее значение SPSR: Потому, что там содержится "ничто" которое отлично отправляется в "никуда". Я бы не отказался и от обратной возможности - записи "ничего", а то бывает приходится писать, например, Код VICVectAddr = i; // Dummy write to signal end of interrupt при этом необходимость комментариев это мелочь, а вот умозрительный подбор расходной регистровой переменной не радует. Цитата spiContext.LastSpsrVal = SPSR; производительности-то оно не сожрет. Да? Вместо, например, команды чтения в первый попавшийся расходный регистр будет производится считывание (для load/store через тот-же промежуточный регистр) в структуру находяшуюся в памяти..... Цитата Даже те "кто в танке" сразу поймут, что делается с SPSR. Угу, приходишь в магазин, а там на бутылке с маслом надпись масло(масло); Начинаешь думать, а чего это вдруг так написали - может смысл какой есть? Смотришь header спрашиваешь и тебе объясняют,что это масло для танкистов....  . В общем-то конечно можно макрос написать, но лишняя сущность.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Dec 25 2008, 11:19
|

читатель даташитов
   
Группа: Свой
Сообщений: 853
Регистрация: 5-11-06
Из: Днепропетровск
Пользователь №: 21 999

|
Цитата(zltigo @ Dec 25 2008, 10:21)  Я бы не отказался и от обратной возможности - записи "ничего", а то бывает приходится писать, например, Код VICVectAddr = i; // Dummy write to signal end of interrupt А почему не так: Код VICVectAddr = 0; Чтобы избежать лишнего обращения к константе? По-идее будет взята из генератора констант...
|
|
|
|
|
Dec 25 2008, 11:42
|

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

|
Цитата(HARMHARM @ Dec 25 2008, 14:19)  Код VICVectAddr = 0; Чтобы избежать лишнего обращения к константе? По-идее будет взята из генератора констант... Полноразмерная Константа будет взята из памяти, или сгенерирована в регистре, но все это уже громоздко по сравнению с минималистичной записью первого попавшегося регистра c произвольным значением. По этой причине и указываю имя некой "недалеко" находящейся переменной.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Dec 25 2008, 13:29
|

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

|
Цитата(zltigo @ Dec 25 2008, 10:21)  Научите  у LPC2000 за тем-же SPI есть FIFO которое - не отключается - нет возможности сбросить его Как сделать запись по SPI так, что-бы когда-нибудь при чтении можно было прочтать SPI, а не содержимое забитого при записи FIFO. Думаю, счетчик отправленных байт должен помочь. Драйвер будет вытаскивать из FIFO ровно то количество байт, которое он запихнул при записи. Цитата Я бы не отказался и от обратной возможности - записи "ничего", а то бывает приходится писать, например, Код VICVectAddr = i; // Dummy write to signal end of interrupt при этом необходимость комментариев это мелочь, а вот умозрительный подбор расходной регистровой переменной не радует. Можно дать константу (опять же если производительности хватает). VICVectAddr = 0; или VICVectAddr = CurrentVector; будет чуть-чуть дольше, зато интуитивно понятно, что делается. Цитата Да? Вместо, например, команды чтения в первый попавшийся расходный регистр будет производится считывание (для load/store через тот-же промежуточный регистр) в структуру находяшуюся в памяти..... Да, тут сознательно добавляем запись в память. Медленнее чем в регистр - да, сильно скажется на производительности всей системы - нет! (всего лишь запись одной ячейки на FIFO циклов SPI). Польза от этой записи - когда свалимся в DABT, можно будет снять дамп и посмотреть состояние железа, в т.ч. и значение SPSR (вдруг именно его значение поможет найти причину аборта). Я говорю не отказаться, а свести к минимуму потребность в пустых чтениях, пустых переменных, и прочем дурном коде, и чтобы не быть пустословным показываю как можно этого добиться. А выбор делать так или нет - как всегда за разработчиком. Цитата(zltigo @ Dec 25 2008, 10:21)  Угу, приходишь в магазин, а там на бутылке с маслом надпись масло(масло);  Ну всяко лучше так, чем взять банку с желтым содержимым без надписи и понять что это совсем не масло, когда содержимое уже плеснули на сковородку.  Цитата В общем-то конечно можно макрос написать, но лишняя сущность. Дело привычки. Например как Вы поступите если есть некий шаблон колбека: Код typedef void (*putmsg_cb)(char *, int, int) и куча функций подпадающих под этот шаблон, но не использующих все параметры? Мне удобно поступать так: Код void xx_putmsg( char *msg, int size, int priority) { ignore( priority ); // <-- избавились от warning'a и сразу видно, что параметр priority нафиг не нужен ... }
|
|
|
|
|
  |
4 чел. читают эту тему (гостей: 4, скрытых пользователей: 0)
Пользователей: 0
|
|
|