我有以下的C代码:

#define PRR_SCALE 255
...
uint8_t a = 3;
uint8_t b = 4;
uint8_t prr;
prr = (PRR_SCALE * a) / b;
printf("prr: %u\n", prr);

如果我编译该(使用MSP430平台的编译器,用于称为半自助旅游旅行社一个小的嵌入式OS )的结果为0,而我预期191。 (uint8_t被Typedef的为unsigned char)

如果我将其更改为:

uint8_t a = 3;
uint8_t b = 4;
uint8_t c = 255;
uint8_t prr;
prr = (c * a) / b;
printf("prr: %u\n", prr);

它的工作原理正确输出并打印191。

编译此“正常”使用gcc的简单版本的Ubuntu盒打印在这两种情况下的正确的值。

我不知道是什么原因,这是。我可以通过预先分配定义的值给变量绕过它,但我宁愿不这样做。

有谁知道这是为什么?也许有一个关于这个链接一些信息呢?

有帮助吗?

解决方案

答案很简单:你的编译器是马车。 (没有与溢出没有问题,正如其他建议。)

在这两种情况下,运算在int,这是保证是至少16位长进行。在前者的片段,那是因为255int,后者是因为积分的推广

如你所指出的,GCC正确处理这一点。

其他提示

255正在处理作为文字的整数,并使得整个表达式为int基于而不是无符号字符为主。第二种情况迫使类型是正确的。试着改变你的#define如下:

 #define PRR_SCALE ((uint8_t) 255)

如果所讨论的编译器是MSPGCC,它应该与二进制/ hex文件熄已编译的程序的汇编程序列表一起。其他编译器可能需要额外的编译器标志来做到这一点。或者甚至一个单独的反汇编器上的二进制运行。

这是地方去寻找一个解释。 由于编译器优化,呈现给所述处理器的实际代码可能具有不多相似性的C原码(但通常做相同的工作)。

通过几个汇编指令步进表示故障代码应揭示问题的原因。

我的猜测是,编译器以某种方式优化了整个计算SICE定义的常量是在编译时已知部分。 255 * X可以优化为x << 8-X(其为更快,更小) 也许有人与优化的汇编代码走错了。

我把编译我的系统上两个版本的时间。与活性优化,MSPGCC产生以下代码:

#define PRR_SCALE 255
uint8_t a = 3;
uint8_t b = 4;
uint8_t prr;
prr = (PRR_SCALE * a) / b;
    40ce:   3c 40 fd ff     mov #-3,    r12 ;#0xfffd
    40d2:   2a 42           mov #4, r10 ;r2 As==10
    40d4:   b0 12 fa 6f     call    __divmodhi4 ;#0x6ffa
    40d8:   0f 4c           mov r12,    r15 ;
printf("prr: %u\n", prr);
    40da:   7f f3           and.b   #-1,    r15 ;r3 As==11
    40dc:   0f 12           push    r15     ;
    40de:   30 12 c0 40     push    #16576      ;#0x40c0
    40e2:   b0 12 9c 67     call    printf      ;#0x679c
    40e6:   21 52           add #4, r1  ;r2 As==10

我们可以看到,编译器直接计算的255 * 3至-3(0xfffd)的结果。这里是问题。不知怎的,255被解释为-1签署的255 16位无符号的8位来代替。或者,它被解析以8位,然后再符号扩展到16位。或任何。

在这个话题的讨论已经在已经在MSPGCC邮件列表开始。

我不知道为什么规定是不行的,但你可能会运行与uint8_t变量翻车。 255是用于uint8_t (2^8 - 1)的最大值,因此,如果乘上3,您一定碰到一些细微的翻转问题。

编译器可能会被优化代码,并预先计算你的数学表达式的结果和在PRR顺手把结果(因为它适合,即使中间值不适合)。

检查,如果你打破了你的表情像这样的(这不会表现得像你想要的)会发生什么:

prr = c * a; // rollover!
prr = prr / b;

您可能需要只使用一个更大的数据类型。

一个区别我能想到的情况下-1是

在PRR_SCALE文字值可能会进入ROM或代码区。并且可以有用于说,在MUL操作码一些差异,

case-1: [register], [rom]
case -2: [register], [register]

有可能没有意义的。

scroll top