Consider the following program:
using namespace std;
int main()
{
uint8_t b = 150;
int8_t a = -10;
if (a>b){
cout << "greater" << endl;
}
else{
cout << "less" << endl;
}
return 0;
}
In Online C 14 Compiler it prints less
. The same result I get in Compiler Explorer with x86-64 gcc 12.2
According to the documentation
Otherwise, the operand has integer type (because bool, char, char8_t, (since C 20) char16_t, char32_t, (since C 11) wchar_t, and unscoped enumeration were promoted at this point) and integral conversions are applied to produce the common type, as follows:
- If both operands are signed or both are unsigned, the operand with lesser conversion rank is converted to the operand with the greater integer conversion rank.
- Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.
- Otherwise, if the signed operand's type can represent all values of the unsigned operand, the unsigned operand is converted to the signed operand's type.
- Otherwise, both operands are converted to the unsigned counterpart of the signed operand's type.
In the Compiler Explorer with x86-64 gcc 12.2 I've compiled it and got the following result:
.LC0:
.string "greater"
.LC1:
.string "less"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov BYTE PTR [rbp-1], -106
mov BYTE PTR [rbp-2], -10
movsx edx, BYTE PTR [rbp-2]
movzx eax, BYTE PTR [rbp-1]
cmp edx, eax
jle .L2
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
jmp .L3
...
So, accoring to
mov BYTE PTR [rbp-1], -106
mov BYTE PTR [rbp-2], -10
uint8_t b
is converted to int8_t
and is assigned a value of -106
, which seems to be true, because it falls under the point 3. of the documentation:
Otherwise, if the signed operand's type can represent all values of the unsigned operand, the unsigned operand is converted to the signed operand's type.
If I understood the documentation and the assembly code right, the comparison
(a>b) //-10 > -106
Should return true. But apparently, it returns false since I get the output of the else
branch.
So my questions is: why is (a>b)
returns false in this example?
CodePudding user response:
You forgot about integral promotion. From https://en.cppreference.com/w/cpp/language/operator_arithmetic :
If the operand passed to an arithmetic operator is integral or unscoped enumeration type, then before any other action (but after lvalue-to-rvalue conversion, if applicable), the operand undergoes integral promotion.
From https://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_promotion :
prvalues of small integral types (such as char) may be converted to prvalues of larger integral types (such as int)
Both a
and b
are first promoted to int
, and then they are compared. As an int
.