Цитата(Д_М @ Jun 23 2013, 01:01)

После долгих поисков выявил, что когда умножаются два числа int, а частное long, старшие 16 бит частного всегда равны нулю. Когда сделал множителе тоже long всё нормально. Как-то странно. Другие компиляторы наоборот выдают придупреждения, когда разрядность частного не больше, чем разрядность множителей - char/int, или int/long...
Это правила языка C таковы - операции над int-операндами он делает в разрядной сетке int, и не обязан расширять результат до long, даже если тот в int не помещается. Другое дело, если один из операндов уже long, тогда и второй операнд тоже будет приведен к типу long, и операция между ними будет произведена в разрядной сетке long. Т.е. забота о типах - это дело программиста, а не компилятора. И если результат умножения двух int-сомножителей требуется перемножать, как long, то следует хотя бы один из сомножителей конвертировать в long-тип явно. Например, так:
Код
int m=20000, n=30000;
long result = (long)m*n;
Причем, понимать эту запись надо не так, что преобразование типа (long) конвертирует результат умножения m*n в long, а так, что оно конвертирует первый сомножитель m из типа int в тип long, после чего компилятор обязан будет их перемножать, как long'и.
Далее. Вы ошибаетесь, в утверждении "другие компиляторы выдают придупреждения, когда разрядность частного не больше, чем разрядность множителей - char/int, или int/long...". Предупреждения выдаются в противоположном случае - когда результат операции не лезет туда, куда его пытаются положить. Вот тогда компилятор и предупреждает о вынужденном округлении или усечении результата. А присваивание короткого длинному вполне законно.
Случай
int = int/long
выдаст предупреждение, но исключением он не является, т.к. здесь один из операндов деления (делитель) имеет тип long, что, в соответствии с правилами, приведет к выполнению деления в разрядной сетке long. По этой причине и результат деления тоже получится long. А засовывание long-результата (частного) в int будет сопровожаться предупреждением о вынужденном урезании. По той же причине результат char/int назад в char без предупреждения не полезет, поскольку будет формально считаться уже int'ом.
Рекомендация вам будет такая: обращайте внимание на то, какого типа у вас операнды. Именно это определяет разрядную сетку, в которой произойдет операция, а вовсе не то, большие числа у вас там лежат или маленькие. Ведь это же компилятор, а не интерпретатор, а потому он компилирует, заранее не анализируя, какие там получатся числа. Об этом должен думать программист, а не компилятор. Например:
Код
int m=20000
long n=1000;
long result = m/n;
Такая запись предупреждения не вызовет, но откомпилируется неоптимально (долго для 8-битников), т.к. делитель типа long обязывает компилятор и делимое тоже превратить в long, а потом делить их друг на друга в разрядной сетке long. Но вы-то понимаете, что результат m/n целочисленен и длиннее int быть не может. Тогда вы должны подсказать компилятору, что n у вас короче long'а:
Код
int m=20000
long n=1000;
long result = m/(int)n;
В последней записи вы сами явно усекаете n до int, чем разрешаете компилятору делить в разрядной сетке int (более быстро).
И наконец. Для умножения char на char с получением результата типа int в компиляторе IAR существует предельно эффективный способ, минуя необходимость совершать умножение в разрядной сетке int. Речь идет встроенных функциях
__intrinsic unsigned int
__multiply_unsigned(unsigned char, unsigned char);
__intrinsic signed int
__multiply_signed(signed char, signed char);
__intrinsic signed int
__multiply_signed_with_unsigned(signed char, unsigned char);
описанных в хидере intrinsics.h
Эти функции позволяют при умножении обходить правила языка C для бинарных операций. Однако для деления таких функций нет.