Я пытаюсь выяснить, гарантирует ли Стандарт C (C90, хотя я отделываюсь от Derek Jones, аннотировал книгу C99), что я не потеряю точность, умножающую два неподписанных 8-разрядных значения и хранящую к 16-разрядному результату. Оператор в качестве примера следующие:
unsigned char foo;
unsigned int foo_u16 = foo * 10;
Наш компилятор Keil 8051 (v7.50 в настоящее время) генерирует инструкцию MUL AB, которая хранит MSB в регистре B и LSB в аккумуляторе. Если я бросил нечто к неподписанному интервалу сначала:
unsigned int foo_u16 = (unsigned int)foo * 10;
затем компилятор правильно решает, что я хочу неподписанный интервал там, и генерирует дорогой вызов к целому числу на 16x16 битов, умножают стандартную программу. Я хотел бы спорить вне обоснованного сомнения, что эта защитная мера не необходима. Когда я считал целочисленные продвижения, описанные в 6.3.1.1, эффект первой строки должен состоять в том, как будто нечто и 10 были продвинуты на неподписанный интервал, умножение, выполненное, и результат, сохраненный как неподписанный интервал в foo_u16. Если компилятор знает инструкцию, которая делает 8x8-> умножение на 16 битов без потери точности, тем лучше; но точность гарантируется. Я читаю это правильно?
С наилучшими пожеланиями, Craig Blome
Продвижение гарантировано, но продвижение осуществляется по типу signed int
, если диапазон unsigned char
попадает в диапазон целое число со знаком
. Итак (при условии, что он подходит) с точки зрения языка ваш
unsigned int foo_u16 = foo * 10;
эквивалентен
unsigned int foo_u16 = (signed) foo * 10;
, в то время как то, что вы, по-видимому, хотите, - это
unsigned int foo_u16 = (unsigned) foo * 10;
. Результат умножения может быть другим, если он (результат) не соответствует диапазон подписанных int
.
Если ваш компилятор интерпретирует это иначе, это может быть ошибка в компиляторе (опять же, в предположении, что диапазон unsigned char
попадает в диапазон signed int
).