uint8_t операции, кога те препълват?

Не съм сигурен кога трябва да се тревожа за препълване, когато използвам неподписани знаци. Този случай е ясен:

uint8_t a = 3;
uint8_t b = 6;
uint8_t c = a - b; // c is 253 

Какво обаче се случва тук:

float d = a - b; // d is -3

И двата a и трябва ли да бъдат преобразувани в float преди извършване на изваждането?

Или също в този случай:

float e = (a - b) + (a - c);

И трите променливи преобразуват ли се в float?

Има ли възможни случаи, при които може да възникне препълване, дори когато променливата, на която е присвоена, е плаваща стойност? Правилата същите ли са, ако e е float, или int, или нещо друго?

Освен това какво се случва в случай като този:

int a = std::abs(a - b);

person Jan Rüegg    schedule 06.08.2015    source източник
comment
неподписаните операции никога не препълват, те просто се обвиват. uint8_t c = a - b; означава uint8_t c = (uint8_t)((int)a - (int)b);, което произвежда опакования резултат след каста   -  person phuclv    schedule 06.08.2015
comment
ЗА да добавите към коментара на @LưuVĩnhPhúc, преливането е лошо, много лошо. Това е недефинирано поведение. Целите числа без знак никога не препълват. Вместо това те използват аритметика по модул 2^n.   -  person David Hammen    schedule 06.08.2015


Отговори (1)


Вашият случай не е резултат от преобразувания от char към float, а се дължи на правилата за насърчаване на цели числа. Cppreference посочва следното (акцентът е мой):

Първите стойности на малки интегрални типове (като char) могат да бъдат преобразувани в първа стойности на по-големи интегрални типове (като int). По-специално, аритметичните оператори не приемат типове, по-малки от int като аргументи, а интегралните повишения се прилагат автоматично след преобразуване от lvalue към rvalue, ако е приложимо. Това преобразуване винаги запазва стойността.

И:

unsigned char или unsigned short може да се преобразува в int, ако може да съдържа целия си диапазон от стойности, и unsigned int в противен случай.

Така че във вашия случай операторът - преобразува стойностите в цели числа, които след това се преобразуват в плаващи числа. Само присвояването на c се преобразува обратно в uint8_t (което препълва).

Същото важи и за примера std::abs: Стойностите се преобразуват преди изваждането и резултатът се предава на функциите.

За повече подробности относно подписани/неподписани промоции на аритметични операции вижте например този отговор: https://stackoverflow.com/a/6770275/3198247

person anderas    schedule 06.08.2015