在 msgpcc(用于 MSP430 微控制器的 GCC)手册中,作者写道:
如果要在函数中使用小整数,请使用 int 而不是 char 或 unsigned char。生成的代码效率更高,并且在大多数情况下,存储实际上并没有被浪费。
为什么int效率更高?
UPD。以及为什么(u)int_fast8_t在 mspgcc 中定义为(unsigned) char,而不是(unsigned) int. 据我了解,(u)int_fast*_t应该定义为具有足够大小的最有效类型。
一般的经验法则是CPU 在处理其原生字长的整数时速度最快。
这当然完全依赖于架构,请参阅这个类似问题的答案以获得关于这一点的更多说明。
TI 已针对其 Tiva-C(原 Stellaris)MCU 发布了有关该主题的应用说明。
在“简介”部分,表格提供了影响性能和大小的因素列表。因子标签可变大小指出“使用小于最佳值的变量可能意味着额外的指令来签名或取消签名扩展...... ”。
此外,在“变量大小”部分下,它指出:
“当局部变量小于寄存器大小时,通常需要额外的代码。在 Stellaris 部分,这意味着大小为字节和半字(分别为 char 和 short int)的局部变量需要额外的代码。因为从8 位或 16 位微控制器可能已将本地变量转换为更小的尺寸(以避免太大的问题),这意味着此类代码将运行得更慢并占用比所需更多的代码空间。”
请参阅:http ://www.ti.com/lit/an/spma014/spma014.pdf
以下由编译器处理,但仍与手头的问题相关:
MSP430 是一个 16 位微处理器。一个字符只有 8 位,需要打包以确保所有字都对齐。例如,3 个字符不会在内存中正确对齐。相反,请使用一个 16 位的整数,并且始终对齐。
当您使用 16 的倍数(例如 16 和 32)的可变大小时,您还可以更有效地利用内存。您最终不会使用填充来对齐内存。
通常,不一定特定于该处理器,它与符号扩展和屏蔽有关,需要额外的指令来忠实地实现 C 源代码。16 位或 32 位或 64 位处理器中的有符号 8 位值可能涉及符号扩展的附加指令。32 位处理器上的 8 位添加可能涉及到 0xFF 和使用 0xFF 等的额外指令等。
你应该做一些简单的实验,它需要几次迭代,但我很快就发现了一些不同的东西。
unsigned int fun ( unsigned int a, unsigned int b )
{
return(a+b)<<3;
}
unsigned char bfun ( unsigned char a, unsigned char b )
{
return(a+b)<<3;
}
int sfun ( int a, int b )
{
return(a+b)<<3;
}
char sbfun ( char a, char b )
{
return(a+b)<<3;
}
生产
00000000 <fun>:
0: 0f 5e add r14, r15
2: 0f 5f rla r15
4: 0f 5f rla r15
6: 0f 5f rla r15
8: 30 41 ret
0000000a <bfun>:
a: 4f 5e add.b r14, r15
c: 4f 5f rla.b r15
e: 4f 5f rla.b r15
10: 4f 5f rla.b r15
12: 30 41 ret
00000014 <sfun>:
14: 0f 5e add r14, r15
16: 0f 5f rla r15
18: 0f 5f rla r15
1a: 0f 5f rla r15
1c: 30 41 ret
0000001e <sbfun>:
1e: 8f 11 sxt r15
20: 8e 11 sxt r14
22: 0f 5e add r14, r15
24: 0f 5f rla r15
26: 0f 5f rla r15
28: 0f 5f rla r15
2a: 4f 4f mov.b r15, r15
2c: 30 41 ret
msp430 具有指令的字和字节版本,因此简单的加法或减法不必执行您在使用小于寄存器大小的变量时所期望的剪裁或符号扩展。作为一名程序员,我们可能知道我们只会提供给 sbfun 一些非常小的数字,但编译器不会并且必须忠实地按照编写的代码实现我们的代码,从而在 sfun 和 sbfun 之间生成更多代码。用不同的编译器和处理器做这些实验并不难看到这一点,唯一的诀窍是创建处理器没有简单指令来解决的代码。
另一个例子
unsigned int fun ( unsigned int a, unsigned int b )
{
return(a+b)>>1;
}
unsigned char bfun ( unsigned char a, unsigned char b )
{
return(a+b)>>1;
}
生产
00000000 <fun>:
0: 0f 5e add r14, r15
2: 12 c3 clrc
4: 0f 10 rrc r15
6: 30 41 ret
00000008 <bfun>:
8: 4f 4f mov.b r15, r15
a: 4e 4e mov.b r14, r14
c: 0f 5e add r14, r15
e: 0f 11 rra r15
10: 4f 4f mov.b r15, r15
12: 30 41 ret
int匹配相关处理器的本机大小(16 位),因此当您请求存储到unsigned char变量时,编译器可能必须发出额外的代码以确保该值介于 0 和 255 之间。