Операции над типами, меньшими int
, выполняются путем преобразования результата в int
, выполнения вычислений, а затем преобразования результата обратно в исходный тип. Для небольших типов без знака при условии, что результат вычисления соответствует типу int
, это приведет к тому, что старшие биты результата будут игнорироваться. Опубликованное обоснование стандарта предполагает, что авторы ожидали, что неархаичные реализации будут игнорировать старшие биты при сохранении значения в тип без знака, который не превышает int
, независимо от того, подойдет ли вычисление для типа int
, но для "современных" компиляторов уже не модно надежно вести себя таким образом. В системе с 16-разрядным коротким и 32-разрядным int
, например, функция
unsigned mulMod65536(unsigned short x, unsigned short y)
{ return (x*y) & 0xFFFFu; }
будет обычно вести себя так же, как:
unsigned mulMod65536(unsigned short x, unsigned short y)
{ return (1u*x*y) & 0xFFFFu; }
но в некоторых случаях gcc будет выполнять "умные" оптимизации, основываясь на том факте, что
разрешается вести себя произвольным образом, если x*y
превышает 2147483647, хотя нет никаких причин, по которым старшие биты должны когда-либо влиять на результат.
Операции с малыми типами со знаком аналогичны операциям, использующим типы без знака, за исключением того, что реализациям разрешено отображать значения, которые превышают диапазон меньших типов, в значения этих типов в режиме, определяемом реализацией, или генерировать сигнал, определяемый реализацией, если сделана попытка преобразовать значение вне диапазона. На практике почти во всех реализациях используется усечение с двумя дополнительными компонентами даже в этом сценарии. В то время как некоторые другие варианты поведения могут быть дешевле в некоторых ситуациях, Стандарт требует, чтобы реализации вели себя согласованно и документально.