unsigned int fun1 ( unsigned int a, unsigned int b )
{
return(a+b);
}
unsigned char fun2 ( unsigned int a, unsigned int b )
{
return(a+b);
}
unsigned int fun3 ( unsigned char a, unsigned char b )
{
return(a+b);
}
unsigned char fun4 ( unsigned char a, unsigned char b )
{
return(a+b);
}
come previsto, fun1 è tutto ints, così come la matematica a 16 bit
00000000 <fun1>:
0: 86 0f add r24, r22
2: 97 1f adc r25, r23
4: 08 95 ret
Anche se tecnicamente errato in quanto è un'aggiunta a 16 bit richiamata dal codice, anche non ottimizzato questo compilatore ha rimosso l'adc a causa delle dimensioni del risultato.
00000006 <fun2>:
6: 86 0f add r24, r22
8: 08 95 ret
non sono davvero sorpreso che la promozione avvenga, i compilatori non erano soliti fare questo non sono sicuri di quale versione abbia avuto inizio, si sono imbattuti così presto nella mia carriera e nonostante i compilatori promuovessero fuori servizio (proprio come sopra), facendo la promozione anche se io gli disse di fare matematica uchar, non sorpreso.
0000000a <fun3>:
a: 70 e0 ldi r23, 0x00 ; 0
c: 26 2f mov r18, r22
e: 37 2f mov r19, r23
10: 28 0f add r18, r24
12: 31 1d adc r19, r1
14: 82 2f mov r24, r18
16: 93 2f mov r25, r19
18: 08 95 ret
e l'ideale, so che è a 8 bit, voglio un risultato a 8 bit, quindi ho semplicemente detto di fare 8 bit fino in fondo.
0000001a <fun4>:
1a: 86 0f add r24, r22
1c: 08 95 ret
Quindi, in generale, è meglio puntare alla dimensione del registro, che è idealmente la dimensione di un (u) int, per un mcu a 8 bit come questo gli autori del compilatore hanno dovuto scendere a compromessi ... Il fatto di non prendere l'abitudine di usare uchar per la matematica che sai non ha bisogno di più di 8 bit come quando sposti quel codice o scrivi un nuovo codice come quello su un processore con registri più grandi ora il compilatore deve iniziare a mascherare e firmare l'estensione, cosa che alcuni fanno in modo nativo in alcune istruzioni, e altri no.
00000000 <fun1>:
0: e0800001 add r0, r0, r1
4: e12fff1e bx lr
00000008 <fun2>:
8: e0800001 add r0, r0, r1
c: e20000ff and r0, r0, #255 ; 0xff
10: e12fff1e bx lr
forzare 8 bit costa di più. Ho imbrogliato un po '/ molto, avrei bisogno di esempi leggermente più complicati per vedere di più in modo equo.
EDIT basato sulla discussione dei commenti
unsigned int fun ( unsigned char a, unsigned char b )
{
unsigned int c;
c = (a<<8)|b;
return(c);
}
00000000 <fun>:
0: 70 e0 ldi r23, 0x00 ; 0
2: 26 2f mov r18, r22
4: 37 2f mov r19, r23
6: 38 2b or r19, r24
8: 82 2f mov r24, r18
a: 93 2f mov r25, r19
c: 08 95 ret
00000000 <fun>:
0: e1810400 orr r0, r1, r0, lsl #8
4: e12fff1e bx lr
nessuna sorpresa. Sebbene perché l'ottimizzatore abbia lasciato quell'istruzione extra, non puoi usare ldi su r19? (Conoscevo la risposta quando l'ho chiesto).
EDIT2
per avr
avr-gcc --version
avr-gcc (GCC) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
per evitare la cattiva abitudine o meno il confronto a 8 bit
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
chiaramente l'ottimizzazione era attiva solo un secondo per provare con il tuo compilatore per vedere come si confronta con il mio output, ma comunque:
whatever-gcc -O2 -c so.c -o so.o
whatever-objdump -D so.o
E sì, l'uso di byte per variabili di dimensioni in byte, certamente su un avr, una foto, ecc., Ti farà risparmiare memoria e vuoi davvero provare a conservarla ... se la stai effettivamente usando, ma come mostrato qui il meno possibile è sarà nella memoria, il più possibile nei registri, quindi il risparmio di flash deriva dal fatto di non avere variabili extra, il risparmio di RAM può essere o non essere reale.