mspgcc 中出现意外结果

发布于 2024-11-06 16:21:43 字数 878 浏览 1 评论 0原文

我用 C 编写了一个简单的代码,但是当我将其移植到 mspgcc 时,它没有给我正确的值。这是我代码的一部分:

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;

我期望的结果是 xk1=443118yk1=49908,但在 mspgcc 中它给了我 xk1=yk1=49902。 不知道类型选择的问题可能出在哪里?

编辑

这是我的完整代码

#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);
}

I wrote a simple code in C, but when I port it to mspgcc it doesn't give me the right value. 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.
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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空袭的梦i 2024-11-13 16:21:43

对于这个编译器来说,整数的大小必须是 16 位,这是一个完全合法的系统。

您预计 xk1 为 443118。443118 % 65536 为 49902。

由于计算:

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

unsigned long int xk1;

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

仅涉及 unsigned Short 值,因此这些值将提升为 unsigned int ,然后将结果计算为 unsigned int,最后将该值分配给 unsigned long。但多余的位早已丢失......计算是通过 16 位无符号算术完成的。


实验

在装有 GCC 4.1.2 的 64 位 RHEL5 (AMD x86/64) 机器上进行。为了模拟 16 位整数计算,我在表达式(的第二个副本)中随意添加了 ((unsigned Short)(...)) 强制转换。双重乘法仅得到一次强制转换;无论两次乘法的执行顺序如何,结果都不会改变(由于被乘数之一为 1,因此不会改变)。我已经将表达式(的第三个副本)包含在 (unsigned long) 转换中。

测试程序:

#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;
}

输出是:

$ 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))
$

我认为第二个几乎不可读的表达式准确地反映(或足够准确地反映)16 位编译器评估该表达式的方式 - 并且与您所看到的一致。

(47541-3588) 的结果是 43953。(10 * 43953) % 65536 的结果是 46314。加上 3588,结果应该是 49902。

我还添加了一个 (unsigned long ) 转换为 yk 并运行表达式。也许为了完全保真您的 32 位 unsigned long 机器,我应该使用 unsigned int,但结果不会改变。我不知道你从哪里获得替代价值 - 我需要查看你的完整工作程序(与我的类似)以获得任何想法。看起来好像你的计算的某些部分“变成负数”,给你留下了大的(正的)无符号值,但是没有明显的理由让计算变成负数。


从注释中获取代码:

#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);
}

65535 应该是 65536。行尾的制表符是不必要的,下一个开头的逗号也是不必要的(但这些都是纯粹的装饰)。

更严重的是(但对当前问题无关紧要,因为它未使用), 定义了一个名为 putchar() 的函数(通常也是宏) >。您可能不应该定义自己的名为 putchar 的函数,但如果必须,您通常应该从 中取消定义宏(假设有一个) 。我承认代码在我的机器上编译正常 - 没有链接,但这是预期的;也许有一天,我会找出这台机器上的 putchar() 到底是什么。

显示的代码产生正确/预期的答案。

我能看到产生观察到的错误行为的唯一方法是这样的,我删除了多余的代码:

#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);
}

当在我的 64 位机器(当前为带有 GCC 4.6.0 的 MacOS X 10.6.7)上运行时,我得到:

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

忽略十六进制值中的 8 个额外 F,我得到 0xFFFCC2EE,而不是您得到的 0xFFFBC2EE。我对这种差异没有任何解释。但您可以看到,如果中间结果是带符号的 16 位数量,那么您最终几乎可以得到您所看到的结果。

那么问题来了:为什么里面会有签名操作呢?我没有很好的解释。我认为您可能需要查看汇编代码并弄清楚发生了什么;您甚至可能会发现编译器中的错误。

The size of an integer must be 16 bits with this compiler, which is a perfectly legitimate system.

You expected xk1 to be 443118. 443118 % 65536 is 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. But the excess bits have long since been lost...the calculation was done in 16-bit unsigned arithmetic.


Experiment

Conducted on a 64-bit RHEL5 (AMD x86/64) machine with GCC 4.1.2. To simulate a 16-bit integer computation, I've liberally laced (a second copy of) the expression with ((unsigned short)(...)) casts. 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). And I've included (a third copy of) the expression with an (unsigned long) cast.

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.

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.

I also added an (unsigned long) cast to yk and ran the expression. Maybe for full fidelity with your machine with 32-bit unsigned long, I should have used unsigned int, but the result doesn't change. 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).

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(). 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>. 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.

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:

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

Ignoring the 8 extra F's in the hex value, I get 0xFFFCC2EE rather than the 0xFFFBC2EE you are getting. 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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文