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);
}
como se esperaba fun1 es todo ints también lo hace la matemática de 16 bits
00000000 <fun1>:
0: 86 0f add r24, r22
2: 97 1f adc r25, r23
4: 08 95 ret
Aunque técnicamente es incorrecto, ya que es una adición de 16 bits invocada por el código, incluso sin optimizar este compilador eliminó el adc debido al tamaño del resultado.
00000006 <fun2>:
6: 86 0f add r24, r22
8: 08 95 ret
No estoy realmente sorprendido de que ocurra la promoción, los compiladores no solían hacer esto, no estoy seguro de qué versión hizo que esto comenzara a ocurrir, me encontré con esto al principio de mi carrera y, a pesar de que los compiladores promocionan fuera de servicio (al igual que arriba), realicé la promoción a pesar de que yo Le dije que hiciera matemáticas uchar, no sorprendido.
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
y lo ideal, sé que es de 8 bits, quiero un resultado de 8 bits, así que simplemente le dije que hiciera 8 bits hasta el final.
0000001a <fun4>:
1a: 86 0f add r24, r22
1c: 08 95 ret
Por lo tanto, en general, es mejor apuntar al tamaño del registro, que es idealmente el tamaño de un (u) int, para un mcu de 8 bits como este, los autores del compilador tuvieron que comprometerse ... El punto es no tener el hábito de el uso de uchar para matemáticas que usted sabe no necesita más de 8 bits, como cuando mueve ese código o escribe un código nuevo como ese en un procesador con registros más grandes, ahora el compilador tiene que comenzar a enmascarar y extender signos, lo que algunos hacen de forma nativa en algunas instrucciones, y otros 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
Forzar 8 bit cuesta más. Hice trampa un poco / mucho, necesitaría ejemplos un poco más complicados para ver más de esto de una manera justa.
EDITAR basado en comentarios discusión
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
No sorpresa. Aunque, ¿por qué el optimizador dejó esa instrucción extra, no puedes usar ldi en r19? (Sabía la respuesta cuando la pregunté).
EDIT2
para 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.
para evitar el mal hábito o no la comparación de 8 bits
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.
claramente la optimización estaba activada solo toma un segundo para probar con su propio compilador para ver cómo se compara con mi salida, pero de todos modos:
whatever-gcc -O2 -c so.c -o so.o
whatever-objdump -D so.o
Y sí, usar bytes para variables de tamaño de byte, ciertamente en un avr, pic, etc., le ahorrará memoria y realmente desea tratar de conservarlo ... si realmente lo está usando, pero como se muestra aquí, lo menos posible es va a estar en la memoria, tanto como sea posible en los registros, por lo que el ahorro flash se produce al no tener variables adicionales, el ahorro de memoria RAM puede o no ser real.