本文大部分涉及到前2个方面:这适用于ARM C compiler。而第三个方面是取决于compiler vendor and compiler revision.所以我们不过多讲述。
基础C数据类型
ARM处理器用于32位的寄存器以及32-bit data processing operations.ARM architecture is a RISC load/store architecture.in other words, you must load or store values from memory into registers before acting on them.ARM没有提供arthmetic or logical instruction to manipulate values in memory directly.
在早期ARM架构中提供了hardware support 用于加载和存储unsigned 8-bit和unsigned or signed 32-bit values.
在ARM中加载值转变为int类型是不需要额外的指令的。LDR等都是直接用于32Bit value的。8-bit 16-bit等都需要先转换为32-bit数据。此外int转换为smaller type does not cost extra instruction on a store.
Because ARM processor were not good at handling signed 8-bit or any 16-bit values.Therefore ARM C compiler define char to be an unsigned 8-bit value, rather than a signed 8-bit values in many other C compilers.编译器也提供了如果你想使char变为signed类型的,在gcc中可以加上 -fsigned-char开启。在armcc则是-zc
C data type
Implementation
char
unsigned 8-bit byte—我在stm32上已经验证过
short
signed 16-bit byte
int
signed 32-bit byte
long
signed 32-bit byte
long long
signed 64-bit double word
local variable type
绝大多数ARM data processing operations are 32-bit only.所以要尽量避免使用short和char,因为这2种类型会产生不必要的转换类型的汇编代码而降低了效率。因此要尽可能的使用32-bit的数据类型,int, long,即使你需要复制一个8-bit,16-bit的值,也要尽可能用int or long.
short checkssum_v4(shor * data)
{
unsignedint i;
int sum = 0;
for(i = 0; i < 64; i++)
{
sum += *(data++);
//如果采用: (效率低的代码)//short sum; sum = (short)(sum+data[i]);//data[i]内部运算的时候就是用了ADD LDRH2个汇编代码,而这个表达式(sum+data[i]结果就是int类型的,所以还需要(short)(sum+data[i])
}
return (short)sum;
}
/*
本段C代码,就是用了3个技巧来提高效率。1.首先循环的i使用了int而不是char之类的。2.其次避免使用data[i]的代码,通过*(data++)减少了一条用于找到&data[i]的汇编代码。3.最后,sum使用int在返回的时候才将其转为short,避免了运算过程中多余的转换。
*/
可以将C function(较小的)和其调用者放到同一个文件中。C compiler may inline the code in the caller。这样可以完全移除function call overhead. 此外也可以在较小的函数前使用inline关键字,这样可以提高效率。但是如果对较大的函数使用_inline会大幅度提高代码尺寸,从而降低效率。
void timer(int * timer1, int * timer2, int *step)
{
*timer1 += *step;
*timer2 += *step;
//这里你可能会觉得汇编指令仅仅复制了一次*step的值。实际上复制了2次*step的值//最高效的办法就是先用一个局部变量存放*step的值。
}
高效:
void timer(int * timer1, int * timer2, int *step)
{
int temp = *step;
*timer1 += temp ;
*timer2 += temp ;
}
使用局部变量保存局部变量的地址
int data;
int sum = 0;
...
data = getdata(&sum); //要避免直接使用变量的地址。
sum++;//因为compiler担心这里有pointer aliasing,所以会在每次改变sum值的时候,都会read and write sum form stack。这样效率很低下。
如果不得不使用局部变量的地址。最好先用一个变量来保存sum的地址,然后使用,比如:
int data;
int sum = 0;
int * sum_addr = ∑
...
data = getdata(sum_addr ); //能有效提高效率
sum++;