Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос к знатокам С.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Страницы: 1, 2
ReAl
Цитата(aaarrr @ Nov 11 2008, 15:31) *
Они там описаны как __io union, никаких volatile в помине нет.

Если это так, то это ошибка того, кто эти h-файлы писал.

Цитата(VladimirYU @ Nov 11 2008, 15:43) *
Разочарую Вас. Сорри, но не умею выделять в окошке кодов:

Ну если так...
А проверьте то же самое с явно заданной
Код
volatile char vch;
а не с SPSR.
Может где-то отвалилась volatile-ность __io_memory
VladimirYU
Цитата(aaarrr @ Nov 11 2008, 16:31) *
Они там описаны как __io union, никаких volatile в помине нет.


Цитата
__io Controls the storage of data objects in I/O memory space, alternatively data memory
space.
The __io memory attribute implies that objects are __no_init and volatile, and allows
objects to be accessed by use of the special I/O instructions in the AVR microcontroller.
Your application may access the AVR I/O system by using the memory-mapped internal
special function registers (SFRs). To access the AVR I/O system efficiently, the __io
memory attribute should be included in the code.
Address range Max object size Pointer size Memory space
0-0x3F 4 bytes (32 bits) Pointers not allowed I/O
0x60-0xFF 4 bytes (32 bits) Pointers not allowed Data
Table 64: I/O address ranges
aaarrr
Цитата(VladimirYU @ Nov 11 2008, 16:43) *
Разочарую Вас.

Интересно. А если принудительно объявить его как volatile? Или провести эксперимент с обычной volatile переменной, как советует уважаемый ReAl?
VladimirYU
Цитата(ReAl @ Nov 11 2008, 16:46) *
Может где-то отвалилась volatile-ность __io_memory

Такой глюк был в версии IAR3.20C, регистры I/O оптимизатор глазом не моргнув кэшировал. Но потом в начиная с 3.20D вроде его исправили.
Попробую просто с обычной переменной.
Цитата
9 int main()
\ main:
10 {
11
12 volatile unsigned char vol_var;
13 vol_var;
14 return 0;
\ 00000000 E000 LDI R16, 0
\ 00000002 E010 LDI R17, 0
\ 00000004 9508 RET
15 }

То же самое

Цитата
9 int main()
\ main:
10 {
\ 00000000 9721 SBIW R29:R28, 1
11
12 volatile unsigned char vol_var;
13 unsigned char novol_var = vol_var;
\ 00000002 8108 LD R16, Y
\ 00000004 2F20 MOV R18, R16
14 return 0;
\ 00000006 E000 LDI R16, 0
\ 00000008 E010 LDI R17, 0
\ 0000000A 9621 ADIW R29:R28, 1
\ 0000000C 9508 RET
15 }
Сергей Борщ
Цитата(VladimirYU @ Nov 11 2008, 16:59) *
То же самое
Рискну повторить вопрос aaarrr из поста №38 - у вас точно не включен режим C++?
aaarrr
Цитата(Сергей Борщ @ Nov 11 2008, 17:05) *
Рискну повторить вопрос aaarrr из поста №38 - у вас точно не включен режим C++?

Да нет, тут дело, похоже, в том, что переменная локальная.
VladimirYU
Цитата(Сергей Борщ @ Nov 11 2008, 17:05) *
Рискну повторить вопрос aaarrr из поста №38 - у вас точно не включен режим C++?


Конечно, Сергей, прав a14.gif
В режиме С все читается нормально, был С++.
ARV
Цитата(aaarrr @ Nov 11 2008, 14:15) *
Ворнинг выдает, т.к. temp не используется после присвоения.
возможно, степень выдачи ворнингов - параноидальная? как мне кажется, это настраивается... WinAVR не выдает ничего с опцией -Wall


off: подозреваю, что все одиозные уязвимости и проблемы Windows вытекают из "виртуозности" кодировщиков, с которой компилятор не справляется biggrin.gif

Цитата(ReAl @ Nov 11 2008, 16:17) *
Что значит "всеми"? Совсем-совсем всеми?
Вот Ваш P.S. с все поймут? Или "все, имеющие уровень образования выше некоторого порога"?
И причём тут маты?
Так что, на мой взгляд, тут скорее "в русском языке много разных способов посттроения предложений, однако для того, чтобы быть понятым всеми, стоит избегать сложных предложений, да и вообще - наличие запятых не ещё не означает, что стоит их ставить в предложениях".
"Все" понимают рекламу, это "хороший стиль рекламы".
Но не все понимают сложный язык литературных произведений, пользующихся всей мощью русского языка и это их хороший стиль. Отменим? Оставим только понимаемые всеми?

а что плохого в том, чтобы быть понятым всеми? или аура "продвинутости" тает при этом? мое мнение: применение "вывертов", которые допускает синтаксис Си, используется исключительно для того, чтобы выделить себя (личность) из ряда прочих (серостей). чем проще изложен алгоритм - тем меньше шансов, что будет допущена логическая ошибка в нем, заодно меньше неоднозначностей при переносе между разными компиляторами. витиеватость кода никак не отражается на оптимальности генерируемых ассемблерных конструкций (если, конечно, эта витиеватость правильно понята компилятором), и разница между i++ и i = i + 1 не видна абсолютно. и если этот пример оправдан хотя бы экономией 2-х (!!!) символов, то применение более "накрученных" штучек мало того что затрудняет восприятие кода другими, но еще может оказаться неверно понятым компилятором... так ради чего сыр-бор?! какова конечная цель: получить всегда гарантированно однозначно воспринимаемый человеком и дающий всегда верный результат код или создать некое произведение искусства, понять которое без опытнейших искуствоведов никто не в силах, и которое транслируется одинаково далеко не во всех случаях?
aaarrr
Цитата(ARV @ Nov 11 2008, 20:18) *
возможно, степень выдачи ворнингов - параноидальная? как мне кажется, это настраивается... WinAVR не выдает ничего с опцией -Wall

Степень нормальная и ворнинг вполне уместный.

Цитата(ARV @ Nov 11 2008, 20:18) *
off: подозреваю, что все одиозные уязвимости и проблемы Windows вытекают из "виртуозности" кодировщиков, с которой компилятор не справляется biggrin.gif

Да, очень легко хаять программистов Майкрософт. А проблемы-то как раз и начинаются с подавления сообщений компилятора.

Цитата(ARV @ Nov 11 2008, 20:32) *
так ради чего сыр-бор?! какова конечная цель: получить всегда гарантированно однозначно воспринимаемый человеком и дающий всегда верный результат код или создать некое произведение искусства, понять которое без опытнейших искуствоведов никто не в силах, и которое транслируется одинаково далеко не во всех случаях?

Цель - не получить сотню-другую "левых" ворнингов при сборке проекта, среди которых так легко теряются "нужные".
ReAl
Цитата(ARV @ Nov 11 2008, 19:32) *
возможно, степень выдачи ворнингов - параноидальная? как мне кажется, это настраивается... WinAVR не выдает ничего с опцией -Wall

-Wall -Wextra, без --pedantic, хотя иногда стоит и его включать.

Цитата(ARV @ Nov 11 2008, 19:32) *
а что плохого в том, чтобы быть понятым всеми? или аура "продвинутости" тает при этом? мое мнение: применение "вывертов", которые допускает синтаксис Си, используется исключительно для того, чтобы выделить себя (личность) из ряда прочих (серостей).
Ну вот, то про маты что-то, то про ауру и выделение личности из серостей... "у кого что болит, тот о том и говорит"?

Написать присваивание какой-то переменной там, где оно не нужно и для переменной, которая больше нигде не используется, или if(UDR); там, где не нужно ничего проверять и рисовать для этого пустое тело if - это не "выверт", это "простое изложение алгоритма"?
Как на мой взгляд, так это как раз выверт для того, чтобы компилятор допёр до того, что надо всё же прочесть.
Приблизительно как FUNC(VAR + 0) в фортране - тоже был некий выверт для обхода неких особенностей.
Но дело в том, что если он не читает просто volatile_var; , то кто гарантирует, что при следующем витке развития он будет продолжать читать if(volatile_var); или temp = volatile_var; ?
Уповать на конкретную особенность конкретного оптимизатора конкретного компилятора - это "тем меньше шансов, что будет ошибка" ?
Да тут не между разными компиляторами, а между разными версиями одного компилятора или даже между разными ключами одной версии может переносимости не быть!

Код
var; // это просто выражение
var+1; // тоже просто выражение
temp = var; // это присваивающее выражение
Все "выражения" (expression) должны быть абстрактной машиной "вычислены" или "оценены" (evaluate)
Цитата
5.1.2.3 Program execution
1 The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant.
2 Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects,11) which are changes in the state of the execution environment. Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations
shall have taken place. (A summary of the sequence points is given in annex C.)
3 In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).
Так вот первые два выражения в примере выше тоже должны быть "evaluated", как и третье.
И если в третьем переменная temp в этом файле нигде больше не используется и не глобальная (глобальность тоже может не помочь, кстати) и var не volatile, то компилятор имеет полное право выбросить его полностью - это не нарушит "observable behavior".
Повторюсь - когда-то давно не выбрасывал и во многих программах работы с аппаратурой вместо описания регистров ка volatile просто делали такое присваивание для принудительного чтения, и тянется жто до сих пор. Но это довольно быстро перестало помогать, как кстати и jmp на следующий адрес для задержки при обращении к медленным портам на PC.
А если var квалифицирована как volatile, то компилятор обязан зачитать её и в первом случае.
Во втором может иметь добрую волю выдать предупреждение, что результат вычисления var+1; нигде не используется, так же как и в третьем имеет право поворчать, что результат присвоения temp нигде не используется и выбросить запись в temp (но при этом обязан прочесть из var).

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

p.s. По крайней мере в случае С.
Надо разобраться, что там с С++ - мне казалось, что базоыве вещи должны были остаться и там, иначе нет той совместимости, которая декларировалась.
ARV
гм... я и не говорил, что пустой if - это норма... я как раз придерживаюсь противоположного мнения... а вот присваивание временной переменной с моей точки зрения - вполне нормальная практика, логичная и не нарушающая никакие стандартны-нормы-правила. volatile тут совсем ни при чем - этот модификатор никто не отменял и его значение (и назначение) не оспаривается.

на счет "специально заведенных переменных"... на сколько я понимаю, при определенном напряжении сил можно очень сложные выражения (например, нечто типа БПФ) уместить в единственном операторе, избежав "лишних" переменных (обычно они называются локальными)... и, хотя с точки зрения результата это будет совершенно верное "выражение", назвать его удобочитаемым будет можно вряд ли. скорее всего и по объему результирующего кода результат не будет отличаться от "развернутого" варианта...

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

можно сколько угодно рассуждать о том, что компилятор "должен сделать", если встретит просто упоминание переменной, но ведь если записать чуть иначе - пропадет сам предмет спора, ибо поведение компилятора станет очевидно на 100%.
ReAl
Если Вам приятно в таком духе - продолжайте, утрируйте, доходите до нелепиц и спорьте с ними - но без меня.
Я вижу разницу между промежуточными переменными для разбивки сложных выражений на более простые и лишними переменными, в которые пишется для того, чтобы никогда из них не читать и этой записью ничего в окружении программы не менять (так как сама эта лишняя переменная - и не SFR и никогда никем не читается).
Если бы эта запись была необходимым или достаточным условием для чтения из переменной в правой части независимо от её volatile-ности, то в этом был бы смысл.
На мой взгляд в такой записи смысла приблизительно столько же, сколько в комментарии
Код
for( i = 0; i < 5; ++i /* инкрементируем счётчик цикла */)
{
}
(хотя для малознакомого с С новичка этот комментарий и повышает читаемость), так как она всего лишь косвенно, через запсиь в другую переменную, говорит "а мы эту переменную прочитали!" для того, кто этого сам не видит. Всего лишь.
gormih
a14.gif
Обсуждение напоминает обсуждение кода типа
Код
unsigned char a
if (a == a) {a=a;}

"Индийский код..."
Чем не устраивает вариант с просмотром дизассемблерного варианта полученного кода? Все сразу встанет на свои места - что лучше, а что хуже..
ARV
хочу для универсализма сделать версию функции printf() для вывода строки на 7-сегментный индикатор, при этом реализация получается примерно такая:
Код
void printf_7led(char *format,  ... ){
   char st[20];
   sprintf(&st, format, ???); // вот тут трабла - обозначена вопросами
   // далее мой код, обрабатывающий st[]
}

трабла такая: как передать "хвост" аргументов, полученных на входе в printf_7led непосредственно в вызываемый sprintf?
P.S. Работаю с WinAVR (GCC)
Сергей Борщ
Код
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(;;);
}
ARV
большое спасибо! я вокруг чего-то похожего бродил, но до верного решения так и не дотумкал.
а на счет вывода в поток "дисплея" - мне кажется, это хоть и красивый метод, но для 6-символьного 7-сегментного дисплея наверное слишком избыточный... просто строчку вывел - сразу понятно, что предыдущая затерлась... а при посимвольном выводе надо как-то так же красиво и логично отслеживать момент, когда строка кончилась... не находите?
ReAl
Цитата(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;
         // вывести символ в текущую позицию
    }
}
ARV
Цитата(ReAl @ Dec 11 2008, 11:56) *
Ну избыточный он не этим - на шести символах просто толком негде разгуляться форматными строками с ширинами полей и т.п.
А что касается "отслеживать момент" - да на раз, було бы желание покуражиться.
как раз желания куражиться и не было.
я поступил по первому совету - сделал оберточные функции для sprintf с преобразованием нормальных символов в семисегментные и весьма доволен результатом. на верхнем уровне и для семисегментника пишу printf_7led("%.2u", var) - и все выводится smile.gif а когда надо, то и так работает printf_7led("stop"). жаль, не все буквы в семисегментные варианты преобразуются smile.gif особенно кириллица - слишкам многа букафф smile.gif
zltigo
Цитата(ARV @ Dec 12 2008, 10:09) *
...сделал оберточные функции для sprintf

http://electronix.ru/forum/index.php?showtopic=56439&hl=
ARV
Цитата(zltigo @ Dec 12 2008, 10:15) *
ну да, это и имел ввиду - vsprintf конечно
defunct
Цитата(ARV @ Nov 11 2008, 22:02) *
практика заведения "лишних" переменных лишь для того, чтобы алгоритм вырисовывался четко и ясно с моей точки зрения вполне разумна и оправдана. а компилятор пускай соптимизирует явную избыточность - на то он и компилятор. кстати, весьма оправдан и подход, когда даже небольшие кусочки алгоритма оформляются отдельными функциями - лишь бы наглядность кода была на должном уровне.

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

Во-первых избегать появления дурного кода - т.е. сводить в минимуму потребность в таких вот "var;" и лишних переменных. С какого бодуна драйвер решил вдруг опустошить содержимое буферов? Ведь можно построить драйвер так, что тупое опустошение не понадобится вовсе! Или почему SPSR надо обязательно читать в никуда?
Можно же хотя бы в целях статистики хранить последнее значение SPSR:
Код
ISR()
{
   ...
   spiContext.LastSpsrVal = SPSR;
}

производительности-то оно не сожрет.

во-вторых - применять практику самодокументируемого кода - завести однозначно понятные макросы:
Код
#define access( x )  // обращение к X
#define ignore( x )  // игнорировать x
...


Встретив в коде
Код
access( SPSR );

Даже те "кто в танке" сразу поймут, что делается с SPSR.
А столкнувшись с "финтом" компилятора - достаточно поменять только тело макроса...
zltigo
Цитата(defunct @ Dec 25 2008, 03:06) *
С какого бодуна драйвер решил вдруг опустошить содержимое буферов? Ведь можно построить драйвер так, что тупое опустошение не понадобится вовсе!

Научите sad.gif у LPC2000 за тем-же SPI есть FIFO которое
- не отключается
- нет возможности сбросить его
Как сделать запись по SPI так, что-бы когда-нибудь при чтении можно было прочтать SPI, а не содержимое забитого при записи FIFO.
Цитата
Или почему SPSR надо обязательно читать в никуда?
Можно же хотя бы в целях статистики хранить последнее значение SPSR:

Потому, что там содержится "ничто" которое отлично отправляется в "никуда".
Я бы не отказался и от обратной возможности - записи "ничего", а то бывает приходится писать, например,
Код
VICVectAddr = i;            // Dummy write to signal end of interrupt

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

Цитата
spiContext.LastSpsrVal = SPSR;
производительности-то оно не сожрет.

Да? Вместо, например, команды чтения в первый попавшийся расходный регистр будет производится считывание (для load/store через тот-же промежуточный регистр) в структуру находяшуюся в памяти.....
Цитата
Даже те "кто в танке" сразу поймут, что делается с SPSR.

Угу, приходишь в магазин, а там на бутылке с маслом надпись
масло(масло);
Начинаешь думать, а чего это вдруг так написали - может смысл какой есть? Смотришь header спрашиваешь и тебе объясняют,что это масло для танкистов.... smile.gif. В общем-то конечно можно макрос написать, но лишняя сущность.
HARMHARM
Цитата(zltigo @ Dec 25 2008, 10:21) *
Я бы не отказался и от обратной возможности - записи "ничего", а то бывает приходится писать, например,
Код
VICVectAddr = i;            // Dummy write to signal end of interrupt

А почему не так:
Код
VICVectAddr = 0;
Чтобы избежать лишнего обращения к константе? По-идее будет взята из генератора констант...
zltigo
Цитата(HARMHARM @ Dec 25 2008, 14:19) *
Код
VICVectAddr = 0;
Чтобы избежать лишнего обращения к константе? По-идее будет взята из генератора констант...

Полноразмерная Константа будет взята из памяти, или сгенерирована в регистре, но все это уже громоздко по сравнению с минималистичной записью первого попавшегося регистра c произвольным значением. По этой причине и указываю имя некой "недалеко" находящейся переменной.
defunct
Цитата(zltigo @ Dec 25 2008, 10:21) *
Научите sad.gif у 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) *
Угу, приходишь в магазин, а там на бутылке с маслом надпись
масло(масло);

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

Цитата
В общем-то конечно можно макрос написать, но лишняя сущность.

Дело привычки. Например как Вы поступите если есть некий шаблон колбека:

Код
typedef void (*putmsg_cb)(char *, int, int)


и куча функций подпадающих под этот шаблон, но не использующих все параметры?

Мне удобно поступать так:

Код
void xx_putmsg( char *msg, int size, int priority)
{
    ignore( priority ); // <-- избавились от warning'a и сразу видно, что параметр priority нафиг не нужен
    ...
}
zltigo
Цитата(defunct @ Dec 25 2008, 16:29) *
Думаю, счетчик отправленных байт должен помочь. Драйвер будет вытаскивать из FIFO ровно то количество байт, которое он запихнул при записи.

Вопрос ведь в том, КУДА ОН ИХ БУДЕТ ДЕВАТЬ после ВЫТАСКИВАНИЯ? Выбрасывать? Вы обещали научить меня писать драйвера
Цитата
.... так, что тупое опустошение не понадобится вовсе!

Если под "умным" опустошением предполагается их, при их априори полной бесполезности тем не менее складывать куда-то дабы "когда свалимся в DABT, можно будет снять дамп и посмотреть", то что тогда назвать безумием smile.gif smile.gif smile.gif
Цитата
будет чуть-чуть дольше, зато интуитивно понятно, что делается.

И дольше и уж абсолютно интуитивно не понятна запись совершенно конкретного нуля, когда на самом деле может быть записано абсолютно произвольное значение sad.gif. В общем это,конечно, мелочи... Но лучше владеть языком так, дабы не было и мелких огрехов, а не уповать на то, что "твоя моя и так понимай если твоя моя понимай однако нада будет".

Цитата(defunct @ Dec 25 2008, 16:29) *
Дело привычки. Например как Вы поступите если есть некий шаблон колбека:
Код
typedef void (*putmsg_cb)(char *, int, int)


и куча функций подпадающих под этот шаблон, но не использующих все параметры?

Мне удобно поступать так:

Код
void xx_putmsg( char *msg, int size, int priority)
{
    ignore( priority ); // <-- избавились от warning'a и сразу видно, что параметр priority нафиг не


Будете смеяться, но мне - удобно АБСОЛЮТНО аналогично smile.gif.
Код
#define argsused(foo) (void)(foo)
argsused( priority );

Только это совсем разные случаи, ибо в описываемый ранее
SPSR;
Абсолютно самодостаточен и не совершенно не нуждается, в отличии от priority, ни в каких мусорных обертках ignore( SPSR ); Если хотите сделать понятным для "танкистов", то напишите комментарий - "танкист" чуть-чуть выглянет из люка и узнает немного нового smile.gif
defunct
Цитата(zltigo @ Dec 25 2008, 16:06) *
Вопрос ведь в том, КУДА ОН ИХ БУДЕТ ДЕВАТЬ после ВЫТАСКИВАНИЯ? Выбрасывать?

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

Цитата
Вы обещали научить меня писать драйвера

Это перебор. Я такого не обещал, к тому же Вы и так умеете их писать.
А порассуждать как можно написать драйвер, чтобы избежать пустых чтений - это пожалуйста. smile.gif

Цитата
Если под "умным" опустошением предполагается их, при их априори полной бесполезности тем не менее складывать куда-то дабы "когда свалимся в DABT, можно будет снять дамп и посмотреть", то что тогда назвать безумием smile.gif smile.gif smile.gif

Под "умным" опустошением понимаем - монотонную работу драйвера. Не ему решать что полезно, а что бесполезно. Принимать без разбора драйвер должен абсолютно все, что физически приходит, и отдавать upper layer'у на рассмотрение.

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

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

if (a || b && c)
или
if (a || (b && c) )
вроде одно и то же, но второе ведь наглядней.

Цитата
Будете смеяться, но мне - удобно АБСОЛЮТНО аналогично smile.gif.

Смеяться не буду, - хорошо, что мы на одной волне в этом вопросе smile.gif

Цитата
Только это совсем разные случаи, ибо в описываемый ранее
SPSR;
Абсолютно самодостаточен и не совершенно не нуждается, в отличии от priority

Я бы не был так категоричен. Потому что SPSR - это не переменная, а макрос. Что там за ним спрятано - хз. Скажете, а UM на что, а если его нет под рукой у читателя кода?

Цитата
ни в каких мусорных обертках ignore( SPSR ); Если хотите сделать понятным для "танкистов", то напишите комментарий - "танкист" чуть-чуть выглянет из люка и узнает немного нового smile.gif

шутку понял smile.gif

Но все же
argused()
ignore()
accessed()
и т.п. делают код прозрачнее, и гибче при переносе.
Сергей Борщ
Цитата(defunct @ Dec 25 2008, 17:32) *
if (a || b && c)
или
if (a || (b && c) )
вроде одно и то же, но второе ведь наглядней.
Это далеко не одно и то же. Логические операции И и ИЛИ всегда выполняются слева направо. Даже компилятор не имеет права изменить этот порядок. Эквивалентным будет if (( a || b ) && c) и со скобками действительно нагляднее.
defunct
Цитата(Сергей Борщ @ Dec 25 2008, 18:09) *
Это далеко не одно и то же. Логические операции И и ИЛИ всегда выполняются слева направо. Даже компилятор не имеет права изменить этот порядок. Эквивалентным будет if (( a || b ) && c) и со скобками действительно нагляднее.

А приоритеты операций?

Все-таки
if (a || b && c)
или
if (a || (b && c) )
это одно и то же.
Если есть время, просимулируйте вот этот тестик:
Код
void test(void)
{
   int a = 1;
   int b = 0;
   int c = 0;

   if (a || b && c )
      printf("1 || (0 && 0)");
   else
      printf("(1 || 0) && 0");
}

У меня результат этого теста - "1 || (0 && 0)". (RVDS 2.2 и 3.1).
Сергей Борщ
Цитата(defunct @ Dec 25 2008, 18:24) *
А приоритеты операций?

Все-таки
if (a || b && c)
или
if (a || (b && c) )
это одно и то же.
Точно. Приоритеты подзабыл. Решил, что у них одинаковый приоритет. Посыпаю голову окурками.
defunct
Цитата(Сергей Борщ @ Dec 25 2008, 19:09) *

Да все в порядке. Как раз хороший пример получился beer.gif - лишний раз подчеркнуть логику работы кода - это только плюс.
ARV
Цитата(defunct @ Dec 25 2008, 20:21) *
Да все в порядке. Как раз хороший пример получился beer.gif - лишний раз подчеркнуть логику работы кода - это только плюс.

как-то натолкнулся на высказывание "в Си скобки лишними не бывают" smile.gif понравилось, следую этому правилу постоянно. голова болит меньше и проблем тоже меньше smile.gif
sonycman
Цитата(zltigo @ Oct 20 2008, 20:17) *
Поскольку регистры uart безвариантно являются и прописаны как volatile, то несомнено второй вариант, ибо явные промежуточные переменные просто совсем не нужны.

Что-то не получается обойтись без временной переменной.
Вот код:
Код
void    i2cStartRead(dword address)
{
    ...
        //dword    temp = I2C2->SR2;
    I2C2->SR2;
}

на что компилер (RV) ругается: i2c.cpp(71): warning: #174-D: expression has no effect

Тот же самый код разложенный по "полочкам":
Код
typedef volatile unsigned short vu16;
typedef unsigned short u16;

typedef struct
{
  vu16 CR1;
  u16  RESERVED0;
  vu16 CR2;
  u16  RESERVED1;
  vu16 OAR1;
  u16  RESERVED2;
  vu16 OAR2;
  u16  RESERVED3;
  vu16 DR;
  u16  RESERVED4;
  vu16 SR1;
  u16  RESERVED5;
  vu16 SR2;
  u16  RESERVED6;
  vu16 CCR;
  u16  RESERVED7;
  vu16 TRISE;
  u16  RESERVED8;
} I2C_TypeDef;

void    i2cStartRead(dword address)
{
        ...
    ((I2C_TypeDef *) (((u32)0x40000000) + 0x5800))->SR2;
}

Как убрать предупреждение компилятора, и обойтись без явной временной переменной?
zltigo
Цитата(sonycman @ Jan 4 2009, 14:12) *
Как убрать предупреждение компилятора, и обойтись без явной временной переменной?

Что-то я совсем не понял, что и как Вы собственно написали sad.gif. А вообще так:
Код
typedef volatile struct
{
    unsigned short SR2;
.....
} I2C_TypeDef;

I2C_TypeDef *I2C2 =  (I2C_TypeDef *)(0x40000000 + 0x5800);

void i2cStartRead(void)
{
....
    I2C2->SR2;

}

P.S.
И вместо мути в структуре ввиде 'reserved' используйте 32bit паковку.
sonycman
Цитата(zltigo @ Jan 4 2009, 18:31) *
Что-то я совсем не понял, что и как Вы собственно написали sad.gif. А вообще так...

P.S.
И вместо мути в структуре ввиде 'reserved' используйте 32bit паковку.

Так эта муть - библиотека ST для STM32. Я из неё использую только определения регистров.
Ну её нафиг переделывать, и так пришлось править, чтобы хидеры из C++ компилировались... smile.gif

Попробовал, как Вы подсказали:
Код
    typedef volatile struct
{
    int    a;
    int    b;
    unsigned short SR2;

} I2C_Type_Def;
    
    I2C_Type_Def * I2C2_1 =  (I2C_Type_Def *)(0x40000000 + 0x5800);

    I2C2_1->SR2;

но компилятор по-прежнему ругается: main.cpp(26): warning: #174-D: expression has no effect
и выкидывает из кода эту строку... 07.gif
zltigo
Цитата(sonycman @ Jan 4 2009, 18:42) *
чтобы хидеры из C++ компилировались... smile.gif

Так что, плюсовым компилируете!? Так тут уже по моему обсуждалось в начале топика - у плюсового свои странные понятия sad.gif....
А такое, тогда он просто молча выкинет?
(void)I2C2_1->SR2;
GetSmart
Цитата(sonycman @ Jan 4 2009, 21:42) *
Попробовал, как Вы подсказали:
Код
    typedef volatile struct
{
    int    a;
    int    b;
    unsigned short SR2;

} I2C_Type_Def;
    
    I2C_Type_Def * I2C2_1 =  (I2C_Type_Def *)(0x40000000 + 0x5800);

    I2C2_1->SR2;

но компилятор по-прежнему ругается: main.cpp(26): warning: #174-D: expression has no effect
и выкидывает из кода эту строку... 07.gif

Впервые вижу волатильную структуру smile.gif Может я ошибаюсь, но только переменная может иметь этот атрибут. Попробуйте объявить так:
Код
    (volatile I2C_Type_Def *)(0x40000000 + 0x5800)->SR2;

Потом проверьте есть ли в листинге чтение этого регистра.

Я написал без временной переменной, но если она нужна или надо делать несколько чтений, то можно так:
Код
    volatile I2C_Type_Def * I2C2_1 =  (volatile I2C_Type_Def *)(0x40000000 + 0x5800);

    I2C2_1->SR2;
zltigo
Цитата(GetSmart @ Jan 4 2009, 19:22) *
но только переменная может иметь этот атрибут...

С чего-бы это вдруг, тем более, что сами написали
volatile I2C_Type_Def * I2C2_1
А если хотели
I2C_Type_Def * volatile I2C2_1
так это совсем другое....
GetSmart
Цитата(zltigo @ Jan 4 2009, 22:27) *
С чего-бы это вдруг, тем более, что сами написали
volatile I2C_Type_Def * I2C2_1
А если хотели
I2C_Type_Def * volatile I2C2_1
так это совсем другое....

Не, не. Я правильно выразил свою мысль в кодеsmile.gif
<<volatile I2C_Type_Def *>> говорит, что там, по адресу будет лежать волатильная структура/переменная. Переменная с адресом (I2C2_1) не должна/обязана быть волатильной. Разглядывая чужие хидеры, например из ИАРа, я ни разу не встречал волатил при объявлении структур, а вот при объявлении переменных - всегда. Поэтому и удивился. Если, теоретически, структуры могут иметь этот атрибут, то возможно проблема у sonycman-а в том, что компилятор не учитывает волатил из структуры, но будет учитывать при непосредственном объявлении в переменной. Проверить-то легко.
zltigo
Цитата(GetSmart @ Jan 4 2009, 20:05) *
то возможно проблема у sonycman-а в том...

Проблема в том, что компилятор плюсовый.


Цитата(GetSmart @ Jan 4 2009, 20:05) *
<<volatile I2C_Type_Def *>> говорит, что там, по адресу будет лежать волатильная структура...

Угу, только почему-то буквально строчкой выше Вы выражали сомнение в возможности описания таких структур smile.gif. О чем речь я и завел.
sonycman
В оригинальной библиотеке для STM32 квалификатор volatile стоит у каждого члена структуры:
Код
typedef volatile unsigned short vu16;
typedef unsigned short u16;

typedef struct
{
  vu16 CR1;
  u16  RESERVED0;
  vu16 CR2;
  u16  RESERVED1;
  vu16 OAR1;
  u16  RESERVED2;
  vu16 OAR2;
  u16  RESERVED3;
  vu16 DR;
  u16  RESERVED4;
  vu16 SR1;
  u16  RESERVED5;
  vu16 SR2;
  u16  RESERVED6;
  vu16 CCR;
  u16  RESERVED7;
  vu16 TRISE;
  u16  RESERVED8;
} I2C_TypeDef;

По совету zltigo я попробовал с квалификатором перед всей структурой:
Код
    typedef volatile struct
{
    unsigned short SR2;
} I2C_Type_Def;

Но, к сожалению, разницы нет.
Такая прикольная конструкция:
Код
(void)I2C2_1->SR2;

действительно молча проглатывается - нет ни предупреждения, ни кода... smile.gif

В общем, буду знать, что C++ не допускает выражений, подобных
...
variable_name_only;
...

laughing.gif
zltigo
Цитата(sonycman @ Jan 4 2009, 21:30) *
Но, к сожалению, разницы нет.

И не должно быть. Я просто по привычке в естественной форме без ненужных излишеств написал.
Сергей Борщ
Цитата(GetSmart @ Jan 4 2009, 19:05) *
Если, теоретически, структуры могут иметь этот атрибут,
Конечно могут, как и любые другие типы данных. Применение модификатора volatile (также как и const) к структуре распространяет его на все члены структуры.

Цитата(zltigo @ Jan 4 2009, 19:49) *
Проблема в том, что компилятор плюсовый.
Точнее это бага плюсового компилятора. Я все-таки залез в стандарт С++, и вот что он пишет:
Цитата
1.9 Program execution
6. The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions.
7. Accessing an object designated by a volatile lvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. [...]
7.1.5.1 The cv-qualifiers
8. [Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the same in C++ as they are in C. ]
sonycman
Цитата(Сергей Борщ @ Jan 4 2009, 23:00) *
Точнее это бага плюсового компилятора. Я все-таки залез в стандарт С++, и вот что он пишет:

Хм, бага? В одной из последних версий RealView?
Неужели никто не использует подобные приёмы обращений к данным?
Тем более из плюсов? 05.gif
sergeeff
Я пробовал такое в MS VS2008 для ARM. Данные читаются, предупреждений никаких.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.