#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: извините — я больше ничего не могу сделать, чтобы помочь вам. Я не понимаю, в чем проблема. Я боюсь (для вас), что решение, вероятно, потребует понимания кода на ассемблере, сгенерированного для вычислений. Я думаю, что именно это я бы сейчас искал, будь это моя проблема.