Arithmetic and Logical Right shift

C, C++, Visual C++, C++.Net Topics
Post Reply
User avatar
SemiconductorCat
Major
Major
Posts: 455
Joined: Mon Aug 22, 2011 8:42 pm
Location: currently in hyperspace

Arithmetic and Logical Right shift

Post by SemiconductorCat » Mon May 06, 2013 5:38 pm

I bet most of the friends here have used the logical shift operator in their code.
But there is a simple difference that we don't mind when we using them.
Specially when we are looking into a code in C/C++ source level we miss such things probably.
But more knowledge is better than little knowledge, so I'm going to dig into the situation with you.


In x86/x64 assembly [however today I'm going to use x64 assembly for examples, I suppose most
of our friends are now using x64 machines] there are two shift instructions, one is arthmetic shift and
other is logical shift.

SAR - shift arithmetic right
Example, SAR RAX , 2 will shift 2 positions right and repeat the sign bit 2 wise.

For a example suppose -35 was in the RAX register then before the instruction,
RAX= 1111111111111111111111111111111111111111111111111111111111011101b
in 64 bit binary.

And after the instruction, it may look like this,
RAX= 1111111111111111111111111111111111111111111111111111111111101110b
which is -18


And supposing the same value on RAX register have gone through SHR instruction , then,
before instruction
RAX= 1111111111111111111111111111111111111111111111111111111111011101b
and after the instruction ,
RAX = 0111111111111111111111111111111111111111111111111111111111101110b
which is equivalent to 9223372036854775790, probably the wrong answer.


However our compiler handles this secretly,
Simply when it uses SAR for signed integer shifting and SLR for unsigned shifting.


Here is a example source code that demonstrates it.

Code: Select all

#include <stdio.h>

int main8(int a, unsigned int b){

 
 // logical shift //
 int c = a >> 2 ;
 int d = b >> 3;


}



Then we generate it's assembly code using the command line '-S' flag.

Code: Select all

$ gcc -S logical_shift_example.c

The resulted assembly instructions are,

Code: Select all

	.file	"left_shift.c"
	.text
	.globl	main8
	.def	main8;	.scl	2;	.type	32;	.endef
	.seh_proc	main8
main8:
	pushq	%rbp
	.seh_pushreg	%rbp
	movq	%rsp, %rbp
	subq	$16, %rsp
	.seh_stackalloc	16
	.seh_setframe	%rbp, 16
	.seh_endprologue
	movl	%ecx, 16(%rbp)
	movl	%edx, 24(%rbp)
	movl	16(%rbp), %eax
	sarl	$2, %eax
	movl	%eax, -4(%rbp)
	movl	24(%rbp), %eax
	shrl	$3, %eax
	movl	%eax, -8(%rbp)
	addq	$16, %rsp
	popq	%rbp
	ret
	.seh_endproc


You could see how the compiler have silently choose appropriate instructions as relevant.

Image

NOTE: when going through the assembly listing just ignore .seh_* directives, They are just directives
to the linker to implement seh structured exception handling[http://msdn.microsoft.com/en-us/library ... 85%29.aspx].


--Thanks for reading--
Post Reply

Return to “C/C++ Programming”