Ответ 1
Итак, я понял:
Ответ очень прост, но понимания позади этого нет.
Ответ:
(как исправить):
Вместо (byte)seconds - tStart
используйте (byte)((byte)seconds - tStart)
. Это! Задача решена! Все, что вам нужно сделать, - это сделать вывод математической операции (вычитание в этом случае) на byte
, а также зафиксировано! В противном случае он возвращается как подписанный int, что приводит к ошибочному поведению.
Итак, почему это происходит?
Ответ:
В C, С++ и С# нет такой вещи, как математическая операция в байте! По-видимому, функции уровня сборки, необходимые для операторов типа +, - и т.д., Не существуют для байтовых входов. Вместо этого все байты сначала неявно передаются (продвигаются) до int перед проведением операции, тогда математическая операция выполняется по ints, а когда она завершается, она возвращает int тоже!
Итак, этот код (byte)seconds - tStart
неявным образом отбрасывается (продвигается в этом случае) компилятором следующим образом: (int)(byte)seconds - (int)tStart
... и он возвращает также int
. Смущает, а? Я так и думал!
Вот еще несколько статей по этому вопросу:
(чем больше звездочек, *, тем полезнее)
- ***** byte + byte = int... почему? < - ОСОБЕННО ПОЛЕЗНО
- ***** Неявные правила преобразования типов в операторы на С++ < - ОСОБЕННО ПОЛЕЗНО. Этот ответ здесь показывает, когда происходят неявные приведения, и говорится: "Примечание. Минимальный размер операций -
int
. Таким образом,short
/char
доint
перед выполнением операции." - ***** Поиск в Google" С++ делает ли нечеткое кастинг при сравнении?
- https://www.tutorialspoint.com/cprogramming/c_type_casting.htm
- http://www.improgrammer.net/type-casting-c-language/
- Поиск Google для "неявного кастинга С++"
- http://www.cplusplus.com/doc/tutorial/typecasting/
- http://en.cppreference.com/w/cpp/language/implicit_conversion
- http://en.cppreference.com/w/cpp/language/operator_comparison
Теперь рассмотрим некоторые реальные примеры на С++:
Вот полная программа на С++, которую вы можете скомпилировать и запустить для проверки выражений, чтобы узнать, что такое тип возврата, и если он был неявным образом передан компилятору к чему-то, чего вы не намерены:
#include <iostream>
using namespace std;
//----------------------------------------------------------------
//printTypeAndVal (overloaded function)
//----------------------------------------------------------------
//UNSIGNED:
void printTypeAndVal(uint8_t myVal)
{
cout << "uint8_t = " << (int)myVal << endl; //(int) cast is required to prevent myVal from printing as a char
}
void printTypeAndVal(uint16_t myVal)
{
cout << "uint16_t = " << myVal << endl;
}
void printTypeAndVal(uint32_t myVal)
{
cout << "uint32_t = " << myVal << endl;
}
void printTypeAndVal(uint64_t myVal)
{
cout << "uint64_t = " << myVal << endl;
}
//SIGNED:
void printTypeAndVal(int8_t myVal)
{
cout << "int8_t = " << (int)myVal << endl; //(int) cast is required to prevent myVal from printing as a char
}
void printTypeAndVal(int16_t myVal)
{
cout << "int16_t = " << myVal << endl;
}
void printTypeAndVal(int32_t myVal)
{
cout << "int32_t = " << myVal << endl;
}
void printTypeAndVal(int64_t myVal)
{
cout << "int64_t = " << myVal << endl;
}
//FLOATING TYPES:
void printTypeAndVal(float myVal)
{
cout << "float = " << myVal << endl;
}
void printTypeAndVal(double myVal)
{
cout << "double = " << myVal << endl;
}
void printTypeAndVal(long double myVal)
{
cout << "long double = " << myVal << endl;
}
//----------------------------------------------------------------
//main
//----------------------------------------------------------------
int main()
{
cout << "Begin\n\n";
//Test variables
uint8_t u1 = 0;
uint8_t u2 = 1;
//Test cases:
//for a single byte, explicit cast of the OUTPUT from the mathematical operation is required to get desired *unsigned* output
cout << "uint8_t - uint8_t:" << endl;
printTypeAndVal(u1 - u2); //-1 (bad)
printTypeAndVal((uint8_t)u1 - (uint8_t)u2); //-1 (bad)
printTypeAndVal((uint8_t)(u1 - u2)); //255 (fixed!)
printTypeAndVal((uint8_t)((uint8_t)u1 - (uint8_t)u2)); //255 (fixed!)
cout << endl;
//for unsigned 2-byte types, explicit casting of the OUTPUT is required too to get desired *unsigned* output
cout << "uint16_t - uint16_t:" << endl;
uint16_t u3 = 0;
uint16_t u4 = 1;
printTypeAndVal(u3 - u4); //-1 (bad)
printTypeAndVal((uint16_t)(u3 - u4)); //65535 (fixed!)
cout << endl;
//for larger standard unsigned types, explicit casting of the OUTPUT is ***NOT*** required to get desired *unsigned* output! IN THIS CASE, NO IMPLICIT PROMOTION (CAST) TO A LARGER *SIGNED* TYPE OCCURS.
cout << "unsigned int - unsigned int:" << endl;
unsigned int u5 = 0;
unsigned int u6 = 1;
printTypeAndVal(u5 - u6); //4294967295 (good--no fixing is required)
printTypeAndVal((unsigned int)(u5 - u6)); //4294967295 (good--no fixing was required)
cout << endl;
return 0;
}
Вы также можете запустить эту программу здесь: http://cpp.sh/6kjgq
Вот результат. Обратите внимание, что как случай с одиночным беззнаковым байтом uint8_t - uint8_t
, так и с двумя неподписанными байтами uint16_t - uint16_t
каждый из них неявно передается (продвигается) компилятором С++ на 4 -byte подписан тип переменной int32_t
(int
). Это поведение, которое вам нужно заметить. Поэтому результат этих вычитаний отрицательный, что является необычным поведением, которое изначально меня смутило, так как я ожидал, что вместо этого underflow станет вместо него значением без знаковой переменной (так как мы делаем 0 - 1). Чтобы достичь желаемого нижнего уровня, я должен был явно передать результат вывода вычитания в нужный тип без знака, а не только на входы. Однако для случая unsigned int
этот явный листинг результата не требовалось.
Начать
uint8_t - uint8_t:
int32_t = -1
int32_t = -1
uint8_t = 255
uint8_t = 255uint16_t - uint16_t:
int32_t = -1
uint16_t = 65535unsigned int - unsigned int:
uint32_t = 4294967295
uint32_t = 4294967295
Вот еще один пример кратких программ, показывающий, что одиночные беззнаковые байтовые (unsigned char
) переменные продвигаются до подписанных ints (int
) при работе.
#include <stdio.h>
int main(int argc, char **argv)
{
unsigned char x = 130;
unsigned char y = 130;
unsigned char z = x + y;
printf("%u\n", x + y); // Prints 260.
printf("%u\n", z); // Prints 4.
}
Выход:
260
4
Проверьте здесь: http://cpp.sh/84eo