C 在嵌入式平台上,使用无符号int而不是(隐式符号)int是否更有效?

C 在嵌入式平台上,使用无符号int而不是(隐式符号)int是否更有效?,c,architecture,C,Architecture,我养成了在代码中尽可能使用无符号整数的习惯,因为处理器可以对无符号类型进行二次幂除法,而对有符号类型则不行。速度对这个项目至关重要。该处理器以高达40 MIPS的速度运行 我的处理器有一个18周期的除法,但它比单周期桶形移位器需要更长的时间。那么,在这里使用无符号整数是否值得加快速度,还是会带来其他缺点?我使用的是dsPIC33FJ128GP802——微芯片dsPIC33F系列的一员。它对有符号整数和无符号整数都有单周期乘法。它还具有符号和零扩展指令 例如,它在混合有符号整数和无符号整数时生成此

我养成了在代码中尽可能使用无符号整数的习惯,因为处理器可以对无符号类型进行二次幂除法,而对有符号类型则不行。速度对这个项目至关重要。该处理器以高达40 MIPS的速度运行

我的处理器有一个18周期的除法,但它比单周期桶形移位器需要更长的时间。那么,在这里使用无符号整数是否值得加快速度,还是会带来其他缺点?我使用的是dsPIC33FJ128GP802——微芯片dsPIC33F系列的一员。它对有符号整数和无符号整数都有单周期乘法。它还具有符号和零扩展指令

例如,它在混合有符号整数和无符号整数时生成此代码

026E4  97E80F     mov.b [w15-24],w0
026E6  FB0000     se w0,w0
026E8  97E11F     mov.b [w15-31],w2
026EA  FB8102     ze w2,w2
026EC  B98002     mul.ss w0,w2,w0
026EE  400600     add.w w0,w0,w12
026F0  FB8003     ze w3,w0
026F2  100770     subr.w w0,#16,w14

我使用的是C(GCC代表dsPIC。)

我认为我们都需要更多地了解处理器的特性,才能回答这个问题。为什么它不能对有符号整数进行二次幂除法呢?据我记忆所及,两者的操作是一样的。即

10/2=00001010变为00000101

-10/2=11110110转到11111 011

也许您应该编写一些简单的代码来执行无符号除法和有符号除法,并比较编译后的输出

基准测试也是一个好主意。它不需要精确。只要有一个由几千个数字组成的数组,启动一个计时器,开始将它们除以几百万次,并计算所需的时间。如果你的处理器速度快的话,可能需要几十亿次。例如

int s_numbers[] = { etc. etc. };
int s_array_size = sizeof(s_numbers);
unsigned int u_numbers[] = { etc. etc.};
unsigned int u_array_size = sizeof(u_numbers);
int i;
int s_result;
unsigned int u_result;

/* Start timer. */

for(i = 0; i < 100000000; i++)
{
  i_result = s_numbers[i % s_array_size] / s_numbers[(i + 1) % s_array_size];
}

/* Stop timer and print difference. */

/* Repeat for unsigned integers. */
int s_number[]={etc.etc};
int s_array_size=sizeof(s_数);
无符号整数[]={etc.etc.};
无符号整数数组大小=sizeof(u数);
int i;
int s_结果;
无符号整数结果;
/*启动计时器*/
对于(i=0;i<100000000;i++)
{
i_结果=s_数[i%s_数组大小]/s_数[(i+1)%s_数组大小];
}
/*停止计时器和打印差异*/
/*对无符号整数重复此操作*/
写得匆忙,以显示原则,请原谅任何错误


它不会给出精确的基准测试,但应该给出哪个更快的总体概念。

我对处理器上可用的指令集不太了解,但快速看一看,我认为它有可用于算术和逻辑移位的指令,这意味着移位一个有符号值的成本与移位一个无符号值的成本大致相同,并且每次使用移位除以2的幂的成本也应该相同。(关于这一点,我的知识来源于快速浏览针对处理器系列的C编译器的一些内在函数)


也就是说,如果您使用的是要解释为无符号的值,那么您最好将它们声明为无符号。在过去的几年中,我越来越多地使用stdint.h中的类型,通常我最终使用的是无符号版本,因为我的值要么本质上是无符号的,要么我只是将它们用作位数组。

以两种方式生成程序集并计算周期

我猜2的无符号幂除更快,因为它可以根据需要进行右移,而无需担心符号扩展


至于缺点:检测算术溢出,溢出一个有符号类型,因为你在使用unsigned时没有意识到它,等等。没有阻塞,只是需要注意不同的事情。

为什么不使用
typedef
并尝试(和基准测试)两种方法呢?我想你的输出是,“使用有符号或无符号,但不要将它们混合在一起“@Karl Knechtel我的大部分代码可能会与签名int一起中断。而且,如果没有专用线程、有限的计时器资源和连续中断,要对某些东西进行基准测试是相当困难的。@Thomas:如果您的大多数代码都会以有符号整数中断,那么问题是什么?还是说无符号整数?根据我刚刚下载的芯片编程模型的PDF文件,桶移位器支持算术右移。这基本上意味着符号是自动扩展的,因此将负数右移1等于将其除以2。它可以除以有符号整数,如果除数是2的幂,则只需要比无符号整数更长的时间。@AlastairG:但是
246/2=11110110
转到
011111011
。如果某个体系结构的算术移位比逻辑右移或vica右移更好,那么这可能很重要。@AlastairG:右移不能为C99中的
-9/2
之类的除法给出正确的结果-C99指定“向零舍入”,所以这个除法的结果应该是
-4
,但是这个移位会得到
-5
@caf:加1就行了。有符号和无符号除以任意参数需要18个周期,右移和加法只需要2。@Thomas O:1必须有条件地相加,只有在负红利时才需要,这将为比较和分支添加周期。