Помислете за кода
void test(int mode)
{
int32_t a = 0x12345678;
int32_t b = mode ? a*0x10000 : a*0x10000LL;
return b;
}
Ако този метод се извика с mode
стойност нула, кодът ще изчисли дългата дълга стойност 0x0000123456780000 и ще я съхрани в a
. Поведението на това е напълно дефинирано от стандарта C: ако бит 31 от резултата е чист, той ще отреже всички освен долните 32 бита и ще съхрани полученото (положително) цяло число в a
. Ако беше зададен бит 31 и резултатът се съхраняваше в 32-битов int
, а не в променлива от тип int32_t
, внедряването би имало известна свобода, но имплементациите имат право да дефинират int32_t
само ако биха извършили такива стеснителни преобразувания според правила на математиката с допълнение на две.
Ако този метод беше извикан с различна от нула mode
стойност, тогава численото изчисление би дало резултат извън обхвата на стойността на временния израз и като такова би причинило Недефинирано поведение. Докато правилата диктуват какво трябва да се случи, ако изчисление, извършено върху по-дълъг тип, се съхрани в по-кратък, те не посочват какво трябва да се случи, ако изчисленията не се вписват в типа, с който се извършват. Доста неприятна празнина в стандарта (която IMHO трябва да бъде запушена) възниква с:
uint16_t multiply(uint16_t x, uint16_t y)
{
return x*y;
}
За всички комбинации от x
и y
стойности, където стандартът казва нещо за това какво трябва да прави тази функция, стандартът изисква тя да изчисли и върне продуктовия мод 65536. Ако стандартът трябваше да наложи това за всички комбинации от x
и y
стойности 0- 65535 този метод трябва да върне аритметичната стойност на (x*y) mod 65536, това би било задължително поведение, с което 99,99% от съвместимите със стандартите компилатори вече биха били в съответствие. За съжаление, на машини, където int
е 32 бита, стандартът понастоящем не налага изисквания по отношение на поведението на тази функция в случаите, когато аритметичният продукт би бил по-голям от 2147483647. Въпреки че всяка част от междинния резултат извън долните 16 бита ще бъде игнорирана, кодът ще се опита да оцени резултата, използвайки 32-битов тип цяло число със знак; стандартът не налага изисквания какво трябва да се случи, ако компилаторът разпознае, че продуктът ще прехвърли този тип.
person
supercat
schedule
07.05.2015
Secure
, е грешно. Възможно е да интерпретирам погрешно стандарта C. - person Arjun Sreedharan   schedule 19.04.2014