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 espera fun1 es todos los 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 llamada por el código, incluso sin optimizarse, este compilador eliminó el anuncio debido al tamaño del resultado.
00000006 <fun2>:
6: 86 0f add r24, r22
8: 08 95 ret
no está realmente sorprendido de que la promoción ocurra, los compiladores no solían hacer esto, no estaban seguros de qué versión hizo que esto empezara a suceder, me topé con esto al principio de mi carrera y, a pesar de que los compiladores se promocionaron fuera de orden (como en el ejemplo anterior) A pesar de que le dije que hiciera uchar matemáticas, no se sorprendió.
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
Entonces, 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 hacer un compromiso ... No se hacen puntos un hábito de usar uchar para matemáticas que usted sabe que no necesita más de 8 bits como cuando mueve ese código o escribe un nuevo código 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 Algunas instrucciones y otras 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 es de extrañar. Aunque, ¿por qué el optimizador dejó esa instrucción adicional, no puede 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 que la optimización estaba activada solo toma un segundo 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í, el uso de bytes para las variables de tamaño de byte, ciertamente en un avr, pic, etc., le ahorrará memoria y usted realmente desea intentar conservarlo ... si realmente lo está utilizando, pero como se muestra aquí como poco como sea posible, estará en la memoria, tanto en los registros como sea posible, por lo que el ahorro repentino se produce al no tener variables adicionales, el ahorro de RAM puede o no ser real.