Цитата(777777 @ May 7 2008, 10:38)

Если уж нас заботит экономия кода, то с шаблошами лучше не связываться...

Если нас заботит экономия кода, то любой иснтрумент надо применять аккуртано. Многие монстроидальные результаты нынешнего софтостроения связаны не с примененеим С++ вообще или шаболнов в частности, а с бездумным "оттянул-уронил".
Я бы, может, и не влез, если бы не эта последняя фраза, которую я процитировал первой.
Цитата(777777 @ May 7 2008, 10:38)

Здесь создается новая переменная и pDst в нее копируется. Лучше инкрементировать саму pDst, ради этого стоит сделать ее char* и каждый раз при обращении писать преобразование типа.
Никто ничего нового не создаёт.
К моменту использования нового указателя старый уже никому не нужен. Как следствие, его можно "выбросить", а регистры использовать по новой. Чудесным образом, в них уже есть нужное значение и ничего никуда копировать вообще не нужно (ну, за исключением копирования указателя из регистров передачи параметра в указательный регистр, у MSP430 и ARM не было бы и этого).
"Найдите десять отличий"
CODE
#include <stdint.h>
uint8_t get_byte();
void read(void* pDst, uint8_t size)
{
uint8_t *p = (uint8_t*)pDst;
while(size--)
*p++ = get_byte();
}
read:
push r17
push r28
push r29
mov r17,r22
movw r28,r24
rjmp .L2
.L3:
rcall get_byte
st Y+,r24
.L2:
subi r17,1
brcc .L3
pop r29
pop r28
pop r17
ret
CODE
#include <stdint.h>
uint8_t get_byte();
void read(uint8_t* pDst, uint8_t size)
{
while(size--)
*pDst++ = get_byte();
}
read:
push r17
push r28
push r29
movw r28,r24
mov r17,r22
rjmp .L2
.L3:
rcall get_byte
st Y+,r24
.L2:
subi r17,1
brcc .L3
pop r29
pop r28
pop r17
ret
Я нашёл только одно - в порядке копирования аргументов на новые места (впрочем, size можно было и не копировать, но это не имеет отношения к преобразованибю типов и "созданиб нового указателя").
Цитата(777777 @ May 7 2008, 10:38)

Если уж нас заботит экономия кода, то с шаблошами лучше не связываться...

Вернёмся. Для более правдоподобного сравнивания я в каждом варианте прочту каждый вид переменной по нескольку раз.
Чистый С, "без никаких латинских примесей"
CODE
#include <stdint.h>
uint8_t get_byte(void);
// уже выяснили, что тут uint8_t * pdst никакого выигрыша не даёт,
// а void даёт возможность применть макрос READ.
void read(void *pdst, uint8_t n)
{
uint8_t *p = (uint8_t*)pdst;
while(n--)
*p++ = get_byte();
}
#define READ(A) read( &(A), sizeof(A) )
uint8_t c0, c1, c2, c3;
uint16_t w0, w1, w2, w3;
uint32_t d0, d1, d2, d3;
void foo(void)
{
READ( c0);
READ( w0);
READ( d0);
READ( d1);
READ( w1);
READ( c1);
}
void moo(void)
{
READ( c0);
READ( c1);
READ( w0);
READ( w1);
READ( d0);
READ( d1);
}
CODE
avr-gcc -Os -mmcu=atmega88 -S
/* странно, отчёт компилятора там завысил размер этой функции, а тут занизил */
read: /* 14 */
push r17
push r28
push r29
mov r17,r22
movw r28,r24
rjmp .L2
.L3:
rcall get_byte
st Y+,r24
.L2:
subi r17,1
brcc .L3
pop r29
pop r28
pop r17
ret
/* function read size 13 (6) */
moo:
ldi r22,lo8(1)
ldi r24,lo8(c0)
ldi r25,hi8(c0)
rcall read
ldi r22,lo8(1)
ldi r24,lo8(c1)
ldi r25,hi8(c1)
rcall read
ldi r22,lo8(2)
ldi r24,lo8(w0)
ldi r25,hi8(w0)
rcall read
ldi r22,lo8(2)
ldi r24,lo8(w1)
ldi r25,hi8(w1)
rcall read
ldi r22,lo8(4)
ldi r24,lo8(d0)
ldi r25,hi8(d0)
rcall read
ldi r22,lo8(4)
ldi r24,lo8(d1)
ldi r25,hi8(d1)
rcall read
ret
/* function moo size 25 (24) */
foo:
ldi r22,lo8(1)
ldi r24,lo8(c0)
ldi r25,hi8(c0)
rcall read
ldi r22,lo8(2)
ldi r24,lo8(w0)
ldi r25,hi8(w0)
rcall read
ldi r22,lo8(4)
ldi r24,lo8(d0)
ldi r25,hi8(d0)
rcall read
ldi r22,lo8(4)
ldi r24,lo8(d1)
ldi r25,hi8(d1)
rcall read
ldi r22,lo8(2)
ldi r24,lo8(w1)
ldi r25,hi8(w1)
rcall read
ldi r22,lo8(1)
ldi r24,lo8(c1)
ldi r25,hi8(c1)
rcall read
ret
/* function foo size 25 (24) */
/* File "f1.c": code 63 = 0x003f ( 54), prologues 3, epilogues 6 */
/* 64 */
Гадкие, противные, местожрущие шаблоны.
CODE
#include <stdint.h>
uint8_t get_byte();
void read(void* pDst, uint8_t size)
{
uint8_t *p = (uint8_t*)pDst;
do
*p++ = get_byte();
while (--size);
}
template <typename T> void read(T & Dst)
{
read(&Dst, sizeof(T));
}
uint8_t c0, c1, c2, c3;
uint16_t w0, w1, w2, w3;
uint32_t d0, d1, d2, d3;
void foo(void)
{
read( c0);
read( w0);
read( d0);
read( d1);
read( w1);
read( c1);
}
void moo(void)
{
read( c0);
read( c1);
read( w0);
read( w1);
read( d0);
read( d1);
}
CODE
_Z4readPvh: /* 13 */
push r17
push r28
push r29
mov r17,r22
movw r28,r24
.L2:
rcall _Z8get_bytev
st Y+,r24
subi r17,lo8(-(-1))
brne .L2
pop r29
pop r28
pop r17
ret
/* function void read(void*, uint8_t) size 14 (7) */
_Z4readImEvRT_: /* 3 */
ldi r22,lo8(4)
rcall _Z4readPvh
ret
/* function void read(T&) [with T = uint32_t] size 3 (2) */
_Z4readIjEvRT_: /* 3 */
ldi r22,lo8(2)
rcall _Z4readPvh
ret
/* function void read(T&) [with T = uint16_t] size 3 (2) */
_Z4readIhEvRT_: /* 3 */
ldi r22,lo8(1)
rcall _Z4readPvh
ret
/* function void read(T&) [with T = uint8_t] size 3 (2) */
_Z3moov: /* 19 */
ldi r24,lo8(c0)
ldi r25,hi8(c0)
rcall _Z4readIhEvRT_
ldi r24,lo8(c1)
ldi r25,hi8(c1)
rcall _Z4readIhEvRT_
ldi r24,lo8(w0)
ldi r25,hi8(w0)
rcall _Z4readIjEvRT_
ldi r24,lo8(w1)
ldi r25,hi8(w1)
rcall _Z4readIjEvRT_
ldi r24,lo8(d0)
ldi r25,hi8(d0)
rcall _Z4readImEvRT_
ldi r24,lo8(d1)
ldi r25,hi8(d1)
rcall _Z4readImEvRT_
ret
/* function void moo() size 19 (18) */
_Z3foov: /* 19 */
ldi r24,lo8(c0)
ldi r25,hi8(c0)
rcall _Z4readIhEvRT_
ldi r24,lo8(w0)
ldi r25,hi8(w0)
rcall _Z4readIjEvRT_
ldi r24,lo8(d0)
ldi r25,hi8(d0)
rcall _Z4readImEvRT_
ldi r24,lo8(d1)
ldi r25,hi8(d1)
rcall _Z4readImEvRT_
ldi r24,lo8(w1)
ldi r25,hi8(w1)
rcall _Z4readIjEvRT_
ldi r24,lo8(c1)
ldi r25,hi8(c1)
rcall _Z4readIhEvRT_
ret
/* function void foo() size 19 (18) */
/* File "f2.cpp": code 61 = 0x003d ( 49), prologues 3, epilogues 9 */
/* 60 */
Итого вариант с шаблонами версии "если хочеться экономить код" дал
выигрыш в 3 слова программной памяти (лишний rjmp в функции read C-шного варианта не считаем) . Или, на этом участке, около 5%.
Обратите внимание - "проигрыш" шаблонов в сгенерированных при специализации шаблона функциях (9 слов), а выигрыш - при каждом применении шаблонного чтения (1 слово, тут 12 применений, 3 слова выигрыша). И чем больше будет чтений, тем больше будет выигрыш.
"догнать" на С можно, заведя самостоятельно функции и производя "закат солнца вручную".
Перегнать не выйдет.
CODE
#include <stdint.h>
uint8_t get_byte(void);
void read(void *pdst, uint8_t n)
{
uint8_t *p = (uint8_t*)pdst;
while(n--)
*p++ = get_byte();
}
void read_u8(uint8_t *p) { read(p, sizeof(uint8_t) ); }
void read_u16(uint16_t *p) { read(p, sizeof(uint16_t) ); }
void read_u32(uint32_t *p) { read(p, sizeof(uint32_t) ); }
uint8_t c0, c1, c2, c3;
uint16_t w0, w1, w2, w3;
uint32_t d0, d1, d2, d3;
void foo(void)
{
read_u8( &c0);
read_u16( &w0);
read_u32( &d0);
read_u32( &d1);
read_u16( &w1);
read_u8( &c1);
}
void moo(void)
{
read_u8( &c0);
read_u8( &c1);
read_u16( &w0);
read_u16( &w1);
read_u32( &d0);
read_u32( &d1);
}