Ответ 1
Если ваш цельный тип не имеет знака, компилятор оптимизирует его, и результат будет таким же. Если он подписан, что-то другое...
Эта программа:
int mod_signed(int i) {
return i % 256;
}
int and_signed(int i) {
return i & 255;
}
unsigned mod_unsigned(unsigned int i) {
return i % 256;
}
unsigned and_unsigned(unsigned int i) {
return i & 255;
}
будет скомпилирован (от GCC 6.2 с -O3; Clang 3.9 производит очень похожий код) в:
mod_signed(int):
mov edx, edi
sar edx, 31
shr edx, 24
lea eax, [rdi+rdx]
movzx eax, al
sub eax, edx
ret
and_signed(int):
movzx eax, dil
ret
mod_unsigned(unsigned int):
movzx eax, dil
ret
and_unsigned(unsigned int):
movzx eax, dil
ret
Результат сборки mod_signed
отличается от
Если оба операнда для выражения умножения, деления или модуля имеют один и тот же знак, результат будет положительным. В противном случае результат будет отрицательным. Результат указателя операции модуля определяется реализацией.
и AFAICT, большая часть реализации решила, что результат выражения модуля всегда совпадает с знаком первого операнда. См. эту документацию.
Следовательно, mod_signed
оптимизирован для (из nwellnhof комментария):
int d = i < 0 ? 255 : 0;
return ((i + d) & 255) - d;
Логически, мы можем доказать, что i % 256 == i & 255
для всех целых без знака, поэтому мы можем доверять компилятору выполнять его работу.