Стандарты языка С предписывают компиляторам пользовать «быстрое» сравнение, вместо корректного.
То есть в следующем коде согласно всех стандартов языка С переменная res
должна получить значение
0
а не 1
, что крайне непрактично.
unsigned int a = 1;
int b = -1;
int res = (b < a);
Недавно я узнал что существует заметно больше способов корректного сравнения чем я изначально предполагал. Поэтому мне интересен чужой опыт.
Естественно речь о ситуациях где отказаться ни от знаковых, ни от беззнаковых никак нельзя.
Мой основной способ решения этой проблемы через расширение разрядности, так как я в первую очередь имею дело с unsigned char
, но смесь size_t
c ssize_t
или что-то подобное также нередко доставляет неудобства.
Опишите кто и как выкручивается в сложившейся ситуации.
[UPDATE] ассемблерные листинги к классическим алгоритмам сравнения
For example x86 gcc 7.1 will for C++ source:
bool compare(int x, unsigned int y) {
return (x < y); // "wrong" (will emit warning)
}
bool compare2(int x, unsigned int y) {
return (x < 0 || static_cast<unsigned int>(x) < y);
}
bool compare3(int x, unsigned int y) {
return static_cast<long long>(x) < static_cast<long long>(y);
}
Produce this assembly (godbolt live demo):
compare(int, unsigned int):
cmp edi, esi
setb al
ret
compare2(int, unsigned int):
mov edx, edi
shr edx, 31
cmp edi, esi
setb al
or eax, edx
ret
compare3(int, unsigned int):
movsx rdi, edi
mov esi, esi
cmp rdi, rsi
setl al
ret
Взято вот здесь: