Rozważmy funkcję (jedną z możliwych implementacji), która wyzeruje prawe N bitów niepodpisanej krótkiej wartości (lub dowolnego innego typu bez znaku). Ewentualna realizacja może wyglądać jak następuje:Przesunięcie bitów w lewo i odrzucenie bitów
template<unsigned int shift>
unsigned short zero_right(unsigned short arg) {
using type = unsigned short;
constexpr type mask = ~(type(0));
constexpr type right_zeros = mask << shift; // <-- error here
return arg & right_zeros;
}
int check() {
return zero_right<4>(16);
}
Z tym kodem, wszystkie kompilatory Mam dostęp do skarżą się, w taki czy inny sposób, o możliwym przepełnienia. Clang jest najbardziej wyraźny jeden z następujących jasny komunikat:
error: implicit conversion from 'int' to 'const type' (aka 'const unsigned short') changes value from 1048560 to 65520 [-Werror,-Wconstant-conversion]
Ten kod wygląda dobrze określone i jasne jak dzień do mnie, gdy jeszcze 3 kompilatory skarżą się, staję się bardzo nerwowy. Czy coś mi umyka? Czy jest naprawdę szansa, że dzieje się coś podejrzanego?
P.S. Podczas gdy alternatywne implementacje zerowania lewych bitów X mogą być mile widziane i interesujące, głównym celem tego pytania jest ważność opublikowanego kodu.
@TavianBarnes, nie mogą być promowane na podpisanych wskazówki dla niepodpisanych argumentów. – SergeyA
Nie o to pytasz, ale czymś, o czym możesz chcieć być świadomym (i nie strzeż się), jest to, że jeśli zostawiłeś przesunięcie, niepodpisana liczba całkowita przez 'n' bity, gdzie 'n' jest> = liczba bitów w typ, który zmieniasz, to jest niezdefiniowane zachowanie. –
@SergeyA Ale to wciąż jest problem: wynik "<<" jest int, nie krótki. Konwersja wyniku 'maski << shift' z powrotem na' type' przed przypisaniem powoduje, że błąd zniknie. –