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

#c #gcc #types #unsigned #mspgcc

#c #gcc #типы #без знака #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=%6lxtn,",xk1);
   printf("yk1=%utn,",yk1);
}
  

Комментарии:

1. Насколько велик каждый из этих типов в MSP, т. Е. сколько бит или что такое sizeof(unsigned long int) и т.д.? На самом деле это, вероятно, просто обычная проблема с недостаточно ранним продвижением типа — попробуйте привести sig, de, yk или xk к беззнаковому значению задолго до вычитания / умножения.

2. unsigned short yk = 47541; printf("%d", yk); что вы получаете?

3. беззнаковое короткое значение int равно 2 байтам, беззнаковое длинное значение int равно 4 байтам, я попытаюсь привести переменные

4. printf(«%d», yk) выдает отрицательное значение:-17995, но %x выдает: b9b5

5. «Я попытаюсь привести переменные …». опубликуйте именно то, что вы сделали. Вы можете получить, xk1=yk1=49902 если у вас есть yk и xk есть signed int и xk1 как unsigned short int . Итак, проблема в вашем коде, где вы приводите переменные.

Ответ №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 amp;amp; ./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=%6lxtn,",xk1);
    //printf("yk1=%utn,",yk1);
    printf("xk1 = %6lx = %6un", xk1, xk1);
    printf("yk1 = %6x = %6un", 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 = %6lun", xk1, xk1);
    printf("yk1= %6x = %6un", yk1, yk1);

    xk1=( xk (sig*((short)yk-xk)*de));
    yk1=xk1 % 65536;
    printf("xk1= %6lx = %6lun", xk1, xk1);
    printf("yk1= %6x = %6un", 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 в шестнадцатеричном значении, я получаю 0xFFFCC2EE вместо 0xFFFBC2EE, который получаете вы. У меня нет объяснения этому несоответствию. Но вы можете видеть, что если промежуточным результатом является 16-разрядная величина со знаком, вы можете в конечном итоге получить практически тот результат, который вы видите.

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

Комментарии:

1. Привет, спасибо за ваши ответы, я попытался преобразовать yk в unsigned long, результат, который я получаю, таков: xk1 = fffbc2ee и yk1 = 49898. Тот же результат при приведении всех переменных

2. даже для копирования прошлого для вашего кода результаты отличаются, я использую gcc4.4.3: ` xk1= fffbc2ee = 4294689518 yk1= c2ee = 49902 xk1= c2ee = 49902 yk1= c2ee = 49902`

3. @miria: извините — я больше ничего не могу сделать, чтобы помочь вам. Я не понимаю, в чем проблема. Я боюсь (для вас), что решение, вероятно, потребует понимания кода на ассемблере, сгенерированного для вычислений. Я думаю, что именно это я бы сейчас искал, будь это моя проблема.