简体   繁体   English

mspgcc中的意外结果

[英]unexpected result in mspgcc

I wrote a simple code in C, but when I port it to mspgcc it doesn't give me the right value. 我在C中编写了一个简单的代码,但是当我将它移植到mspgcc时,它并没有给我正确的值。 This is a part of my code: 这是我的代码的一部分:

unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;

unsigned long int xk1;

xk1=( xk+(sig*(yk-xk)*de));

yk1=xk1 % 65535;

the result that I expect is xk1=443118 and yk1=49908 , but in mspgcc it gives me xk1=yk1=49902 . 我期望的结果是xk1=443118yk1=49908 ,但是在mspgcc中它给出了xk1=yk1=49902 I don't know where is the fault may be in the type choice? 我不知道类型选择中的故障可能在哪里?

Edit 编辑

this is my full code 这是我的完整代码

#include <stdio.h>
#include "uart1.h"
#include <stdlib.h> 
#include <stdint.h>
#include <string.h>
#include <math.h>

int putchar(int c)
{
   return uart1_putchar(c);
}

int main(void) 
{
   //variables
   unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
   unsigned long xk1;
   uart1_init();
   xk1=( xk+(sig*((unsigned long)yk-xk)*de));
   yk1=xk1 % 65536;
   printf("xk1=%6lx\t\n,",xk1);
   printf("yk1=%u\t\n,",yk1);
}

The size of an integer must be 16 bits with this compiler, which is a perfectly legitimate system. 使用此编译器,整数的大小必须为16位,这是一个完全合法的系统。

You expected xk1 to be 443118. 443118 % 65536 is 49902. 您预计xk1为443118. 443118%65536为49902。

Since the calculation: 自计算:

unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;

unsigned long int xk1;

xk1=( xk+(sig*(yk-xk)*de));

involves only unsigned short values, these are promoted to unsigned int , then the result is computed as an unsigned int , and finally that value is assigned to the unsigned long . 只涉及unsigned short值,将它们提升为unsigned int ,然后将结果计算为unsigned int ,最后将该值赋给unsigned long But the excess bits have long since been lost...the calculation was done in 16-bit unsigned arithmetic. 但多余的位早已丢失......计算是在16位无符号算术中完成的。


Experiment 实验

Conducted on a 64-bit RHEL5 (AMD x86/64) machine with GCC 4.1.2. 在具有GCC 4.1.2的64位RHEL5(AMD x86 / 64)机器上进行。 To simulate a 16-bit integer computation, I've liberally laced (a second copy of) the expression with ((unsigned short)(...)) casts. 为了模拟一个16位整数计算,我用((unsigned short)(...))强制转换表达了((unsigned short)(...))第二个副本)表达式。 The double multiplication only gets a single cast; 双倍乘法只获得一次演员; the result doesn't change regardless of the order in which the two multiplies are done (doubly not since one of the multiplicands is 1). 无论两次乘法的顺序如何,结果都不会改变(加倍,因为其中一个被乘数是1)。 And I've included (a third copy of) the expression with an (unsigned long) cast. 我已经包含(第三个副本)表达式(unsigned long)演员。

Test program: 测试程序:

#include <stdio.h>

int main(void)
{
    unsigned short int xk=3588, yk=47541, sig=10, de=1;
    unsigned long int xk1;

    xk1 = (xk+(sig*(yk-xk)*de));
    printf("No Cast: %6lu = (%u+(%u*(%u-%u)*%u))\n", xk1, xk, sig, yk, xk, de);
    xk1 = ((unsigned short)(xk+((unsigned short)(sig*((unsigned short)(yk-xk))*de))));
    printf("US Cast: %6lu = (%u+(%u*(%u-%u)*%u))\n", xk1, xk, sig, yk, xk, de);
    xk1 = (xk+(sig*((unsigned long)yk-xk)*de));
    printf("UL Cast: %6lu = (%u+(%u*(%u-%u)*%u))\n", xk1, xk, sig, yk, xk, de);
    return 0;
}

The output is: 输出是:

$ gcc -Wall -Wextra -g -O3 -std=c99 xx.c -o xx && ./xx
No Cast: 443118 = (3588+(10*(47541-3588)*1))
US Cast:  49902 = (3588+(10*(47541-3588)*1))
UL Cast: 443118 = (3588+(10*(47541-3588)*1))
$

I think the second, almost unreadable expression accurately reflects (or sufficiently accurately reflects) the way a 16-bit compiler would evaluate the expression - and the agrees with what you saw. 我认为第二个几乎不可读的表达式准确反映(或足够准确地反映)16位编译器评估表达式的方式 - 并且与您所看到的一致。

The result of (47541-3588) is 43953. The result of (10 * 43953) % 65536 is 46314. Add the 3588, and the result is, as it should be, 49902. (47541-3588)的结果是43953.(10 * 43953)%65536的结果是46314.添加3588,结果是,应该是49902。

I also added an (unsigned long) cast to yk and ran the expression. 我还向yk添加了一个(unsigned long) yk并运行了表达式。 Maybe for full fidelity with your machine with 32-bit unsigned long , I should have used unsigned int , but the result doesn't change. 也许对于具有32位unsigned long unsigned int的机器的完全保真度,我应该使用unsigned int ,但结果不会改变。 I don't know where you got your alternative value from - I'd need to see your full working program (analogous to mine) to get any ideas on that. 我不知道你从哪里获得了替代价值 - 我需要看到你的完整工作计划(类似于我的)以获得任何想法。 It looks as though you had some part of the calculation 'go negative' on you, leaving you with large (positive) unsigned values, but there is no obvious excuse for the computation to go negative. 看起来好像你有一部分计算'去负',留下你的大(正)无符号值,但没有明显的借口使计算变为负数。


Taking the code from the comment: 从评论中获取代码:

#include <stdio.h>
// -unused- #include "uart1.h"
// -unused- #include <stdlib.h>
// -unused- #include <stdint.h>
// -unused- #include <string.h>
// -unused- #include <math.h>

// -unused- int putchar(int c) { return uart1_putchar(c); }

int main(void)
{
    //variables
    unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
    unsigned long xk1;
    // -not-needed-in-demo uart1_init();
    xk1=( xk+(sig*((unsigned long)yk-xk)*de));
    yk1=xk1 % 65535;
    //printf("xk1=%6lx\t\n,",xk1);
    //printf("yk1=%u\t\n,",yk1);
    printf("xk1 = %6lx = %6u\n", xk1, xk1);
    printf("yk1 = %6x = %6u\n", yk1, yk1);
}

The 65535 should be 65536. The tab at the end of the line is unnecessary, as is the comma at the beginning of the next (but these are pure cosmetics). 65535应该是65536.该行末尾的标签是不必要的,就像下一个开头的逗号一样(但这些是纯化妆品)。

More serious (but immaterial to the problem at hand because it is unused), the <stdio.h> defines a function (and usually a macro too) called putchar() . 更严重(但由于它未被使用而对手头的问题无关紧要), <stdio.h>定义了一个名为putchar()的函数(通常也是一个宏putchar() You should probably not be defining your own function called putchar , but if you must, you should normally undefine the macro (assuming there is one) from <stdio.h> . 您可能不应该定义自己的函数putchar ,但如果必须,您通常应该从<stdio.h>取消定义宏(假设有一个)。 I admit the code compiled OK on my machine - didn't link, but that was expected; 我承认在我的机器上编译好的代码 - 没有链接,但这是预期的; one day, maybe, I'll track down what putchar() really is on this machine. 也许有一天,我会追踪putchar()在这台机器上的真正含义。

The code shown produces the correct/expected answer. 显示的代码产生正确/预期的答案。

The only way I can see to produce the observed incorrect behaviour is this, where I've removed the superfluous code: 我可以看到产生观察到的错误行为的唯一方法就是这样,我删除了多余的代码:

#include <stdio.h>

int main(void)
{
    unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
    unsigned long xk1;
    xk1=( xk+(sig*((unsigned long)yk-xk)*de));
    yk1=xk1 % 65536;
    printf("xk1= %6lx = %6lu\n", xk1, xk1);
    printf("yk1= %6x = %6u\n", yk1, yk1);

    xk1=( xk+(sig*((short)yk-xk)*de));
    yk1=xk1 % 65536;
    printf("xk1= %6lx = %6lu\n", xk1, xk1);
    printf("yk1= %6x = %6u\n", yk1, yk1);
}

When run on my 64-bit machine (currently, MacOS X 10.6.7 with GCC 4.6.0), I get: 当我的64位机器(目前,MacOS X 10.6.7与GCC 4.6.0)上运行时,我得到:

xk1=  6c2ee = 443118
yk1=   c2ee =  49902
xk1= fffffffffffcc2ee = 18446744073709339374
yk1=   c2ee =  49902

Ignoring the 8 extra F's in the hex value, I get 0xFFF C C2EE rather than the 0xFFF B C2EE you are getting. 忽略十六进制值中的8个额外F,我得到0xFFF C C2EE而不是你得到的0xFFF B C2EE。 I have no explanation for that discrepancy. 我没有解释这种差异。 But you can see that if the intermediate result is a signed 16-bit quantity, you can end up with pretty much the result you're seeing. 但是你可以看到,如果中间结果是一个带符号的16位数量,那么你最终可能会看到你所看到的结果。

Then the question is: why is there a signed operation in there? 然后问题是:为什么那里有签名操作? I have no good explanation. 我没有很好的解释。 I think you may have to look at the assembler code and work out what is going on; 我想你可能需要查看汇编代码并找出正在发生的事情; you may even be tickling a bug in the compiler. 你甚至可能在编译器中发现一个错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM