Неожиданный результат в mspgcc

Я написал простой код на 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=443118 а также yk1=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);
}

1 ответ

Размер целого числа должен составлять 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-битной беззнаковой арифметике.


эксперимент

Проводится на 64-битной машине RHEL5 (AMD x86/64) с GCC 4.1.2. Чтобы имитировать 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. Вкладка в конце строки не нужна, как и запятая в начале следующей (но это чистая косметика).

Более серьезная (но несущественная для рассматриваемой проблемы, потому что она не используется), <stdio.h> определяет функцию (и обычно макрос тоже) с именем putchar(), Вы, вероятно, не должны определять свою собственную функцию с именем putchar, но если вам нужно, вы обычно должны отменить определение макроса (при условии, что он есть) из <stdio.h>, Я допускаю, что код, скомпилированный на моей машине, в порядке - не связывался, но это было ожидаемо; однажды, может быть, я буду отслеживать, что 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-битной машине (в настоящее время MacOS X 10.6.7 с GCC 4.6.0) я получаю:

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

Игнорируя 8 дополнительных F в шестнадцатеричном значении, я получаю 0xFFFC C2EE, а не 0xFFFB C2EE, который вы получаете. У меня нет объяснения этому расхождению. Но вы можете видеть, что если промежуточный результат представляет собой 16-разрядную величину со знаком, вы можете получить в значительной степени тот результат, который видите.

Тогда возникает вопрос: почему там подписанная операция? У меня нет хорошего объяснения. Я думаю, что вам, возможно, придется взглянуть на ассемблерный код и понять, что происходит; Вы можете даже щекотать ошибку в компиляторе.

Другие вопросы по тегам