int main(){
unsigned long a = 5;
int b = -6;
long c = a b;
return 0;
}
I wanted to follow the rules explined in this link and confirm my understanding
of how the compiler emits code for a b
:
https://en.cppreference.com/w/c/language/conversion
1- b
is first converted to an unsigned long
:
If the unsigned type has conversion rank greater than or equal to the rank of the signed type, then the operand with the signed type is implicitly converted to the unsigned type.
So the the compiler essentially does this:
unsigned long implicit_conversion_of_b = (unsigned long) b;
2- The above implicit conversion itself is covered with this rule under Integer conversions
:
if the target type is unsigned, the value 2b , where b is the number of bits in the target type, is repeatedly subtracted or added to the source value until the result fits in the target type.
3- We finlay end up with these 64-bit values in a register before addition takes place:
a = 0x5
b = 0xfffffffffffffffa
Is the above a correct mapping to the rules?
Edit:
4- The final result is an unsigned long
which needs to be converted to long
needed b c
using this rule:
otherwise, if the target type is signed, the behavior is implementation-defined (which may include raising a signal)
CodePudding user response:
Is the above a correct mapping to the rules?
Yes.
CodePudding user response:
I'm certainly no assembly expert, but it's interesting to see what's happening here. Compiled with gcc -O0
:
main:
// setup stack
push rbp
mov rbp, rsp
// move 5 into 8-byte offset from the stack frame.
// rbp is the stack frame pointer, offset of 8 shows long is 8
// bytes on this architecture
mov QWORD PTR [rbp-8], 5
// move -6 to 12 bytes offset from rbp (or 4 byte offset from
// last value. This tells you int is 4 bytes on this architecture.
mov DWORD PTR [rbp-12], -6
// move the int into eax register. This is a 32-bit general
// purpose register
mov eax, DWORD PTR [rbp-12]
// movsx is a "move with sign extension" instruction. rdx is a
// 64-bit register, so this is your conversion from 32 to 64
// bits, preserving the sign
movsx rdx, eax
// moves 5 to the 64-bit rax register
mov rax, QWORD PTR [rbp-8]
// performs the 64-bit add
add rax, rdx
// not using the result, so cleanup, prepare to return
// from function
mov QWORD PTR [rbp-24], rax
mov eax, 0
pop rbp
ret
This assembly was generated with gcc 11.2