Цитата(Qwertty @ Aug 28 2009, 23:29)

Я видимо чего то не понимаю в этой жизни. Делать обертку для volatile переменной, чтобы ее использовать в прерывании как обычную с помощью union или конструтора и деструктора объекта...
Извините, но чтобы показать, что С++
ничем не лучше, нужно привести опровержения для
всех примеров, а не для одного.
Цитата(Qwertty @ Aug 28 2009, 23:29)

Работа через указатель оставляет полную свободу оптимизатору вплоть до сокращения до нуля всего и вся

Какие минусы по сравнению с Вашим вариантом?
Как в старом анекдоте про молодого специалиста в юридической консультации
Цитата
-- скажите, имею ли я прав...
-- имеете!
-- скажите, а имею ли я пра...
-- имеете!
-- скажите, а мог..
-- не можете!!!
Мало
иметь права оставлять полную свободу, надо ещё чтобы это давало результат.
Даже оставляя за скобками то, что я не люблю не только снятие const приведением указателя, но и снятие volatile (это вопрос несколько "вкусовой") - повторяем пример в такой форме.
Код
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t timer;
ISR(TIMER0_OVF_vect)
{
uint8_t *ptimer = (uint8_t*)&timer;
if( --*ptimer == 0 ) {
*ptimer = 127;
}
if( PINB & 0x02) return; // тут тоже запишется назад изменённое значение
if( *ptimer & 0x01 ) PINB |= 0x01;
}
Получаем тело обработчика в пяти случаях из шести (WinAVR 20060421, 20071221, 20090313) * (-O2 -Os) такое, как будто снятие volatile просто проигнорировано:
Код
.global __vector_16
.type __vector_16, @function
__vector_16:
push __zero_reg__
push __tmp_reg__
in __tmp_reg__,__SREG__
push __tmp_reg__
clr __zero_reg__
push r24
lds r24,timer
subi r24,lo8(-(-1))
sts timer,r24
tst r24
brne .L2
ldi r24,lo8(127)
sts timer,r24
.L2:
sbic 35-0x20,1
rjmp .L1
lds r24,timer
sbrc r24,0
sbi 35-0x20,0
.L1:
pop r24
pop __tmp_reg__
out __SREG__,__tmp_reg__
pop __tmp_reg__
pop __zero_reg__
reti
что на пять слов и несколько тактов длиннее, чем С++ - ный вариант.
И только в одном случае (WinAVR 20060421 -O2, но -O2 в большинстве случаев хуже, чем -Os) имеем вариант, совпадающий с С++ - ным и с таким:
Код
ISR(TIMER1_OVF_vect)
{
uint8_t t = timer;
if( --t == 0 ) {
t = 127;
}
if( PINB & 0x02) {
timer = t;
return;
}
if( t & 0x01 ) PINB |= 0x01;
timer = t;
}
Собственно, С++ просто автоматизировал несложным и недлинным шаблоном такое поведение, которое тут выписано врукопашную.
Так как насчёт остальных примеров?
Вернёмся к атомайзеру.
Берём атомайзер по приведенному выше линку и пишем.
Код
atomic<uint16_t> timer;
void delay(uint16_t tim) {
uint16_t start = timer;
while( (uint16_t)(timer - start) < tim);
}
Получаем код
Код
.text
.global _Z5delayj
.type _Z5delayj, @function
_Z5delayj:
movw r22,r24
in r24,95-0x20
/* #APP */
cli
/* #NOAPP */
lds r20,timer
lds r21,(timer)+1
out 95-0x20,r24
.L2:
in r18,95-0x20
/* #APP */
cli
/* #NOAPP */
lds r24,timer
lds r25,(timer)+1
out 95-0x20,r18
sub r24,r20
sbc r25,r21
cp r24,r22
cpc r25,r23
brlo .L2
ret
Пишем тот же функционал на С
Код
#include <stdint.h>
#include <util/atomic.h>
volatile uint16_t timer;
void delay(uint16_t tim) {
uint16_t start, current;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
start = timer;
}
do {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
current = timer;
}
} while( (uint16_t)(current - start) < tim);
}
И получаем 100% совпадающий код.
Код
.text
.global delay
.type delay, @function
delay:
movw r22,r24
in r24,95-0x20
/* #APP */
cli
/* #NOAPP */
lds r20,timer
lds r21,(timer)+1
out 95-0x20,r24
.L2:
in r18,95-0x20
/* #APP */
cli
/* #NOAPP */
lds r24,timer
lds r25,(timer)+1
out 95-0x20,r18
sub r24,r20
sbc r25,r21
cp r24,r22
cpc r25,r23
brlo .L2
ret
За что боролись, отказываясь от С++ ?
Я видимо чего то не понимаю в этой жизни . Заводить дополнительную переменную, оборачивать код в макросы - чтобы получить тот же функционал, который на С++ пишется парой ясных строчек и при этом не выиграть ни грамма кода по сравненпию с С++...