在x86_64平台上,下面這段**輸出的結果是否相同?
#include #include int main(int argc, char* ar**)
輸出結果:
r0 = 144115188075855872, r1 = 33554432
原因:相關彙編**
0000000000400530 :
400530: 55 push %rbp
400531: 48 89 e5 mov %rsp,%rbp
400534: 48 83 ec 30 sub $0x30,%rsp
400538: 89 7d dc mov %edi,-0x24(%rbp)
40053b: 48 89 75 d0 mov %rsi,-0x30(%rbp)
40053f: c7 45 fc 39 00 00 00 movl $0x39,-0x4(%rbp)
400546: 48 c7 45 f0 01 00 00 movq $0x1,-0x10(%rbp)
40054d: 00
40054e: 8b 45 fc mov -0x4(%rbp),%eax
400551: 48 8b 55 f0 mov -0x10(%rbp),%rdx
400555: 89 c1 mov %eax,%ecx
400557: 48 d3 e2 shl %cl,%rdx
40055a: 48 89 d0 mov %rdx,%rax
40055d: 48 89 45 e8 mov %rax,-0x18(%rbp)
400561: 8b 45 fc mov -0x4(%rbp),%eax
400564: ba 01 00 00 00 mov $0x1,%edx
400569: 89 c1 mov %eax,%ecx
40056b: d3 e2 shl %cl,%edx
40056d: 89 d0 mov %edx,%eax
40056f: 48 98 cltq
400571: 48 89 45 e0 mov %rax,-0x20(%rbp)
400575: 48 8b 55 e0 mov -0x20(%rbp),%rdx
400579: 48 8b 45 e8 mov -0x18(%rbp),%rax
40057d: 48 89 c6 mov %rax,%rsi
400580: bf 30 06 40 00 mov $0x400630,%edi
400585: b8 00 00 00 00 mov $0x0,%eax
40058a: e8 81 fe ff ff callq 400410
從彙編**上可以看到,對於第一條位移語句,使用的是暫存器%rdx(64位)儲存位移結果;而第二條位移語句,使用暫存器%edx(32位)儲存位移結果,然後再通過cltq指令,將結果擴充套件到64位。
因為對於32位的數字移57位會發生溢位
實際%edx儲存值為((uint64_t)1 << 57) % ((2^32)-1) = 144115188075855872 % 4294967295 = 33554432
cltq r[%rax ] <- signextend(r[%eax]) convert %eax to quad word,將$eax轉化為8字,即%rax。
cltq是有符號數的擴充套件,如果%eax的最高的32位為1的話,剛%eax的高32擴充套件後全為1;相反如果%eax的高位為0的話,則擴充套件出來後全為0。
關於移位操作
左移 不管是有符號數還是無符號數,數字都往左移動n位,右邊用0補足。如果左移的位數超過整數本身的位數,結果不知道。vs上測試結果是從頭開始。例子 vs,32位機器 int型別,原始值0x1,左移31位後是0x80000000。左移32位後是0x1。原始值0x11,左移31位後是0x80000000,...
c中的移位操作
位移位運算子是將資料看成二進位制數,對其進行向左或向右移動若干位的運算。位移位運算子分為左移和右移兩種,均為雙目運算子。第一運算物件是移位物件,第二個運算物件是所移的二進位制位數。位移位運算子的運算物件 運算規則與結果 結合性如表2 16所示。移位時,移出的位數全部丟棄,移出的空位補入的數與左移還是...
c語言的移位操作
左移時總是移位和補零。右移時無符號數是移位和補零,此時稱為邏輯右移 而有符號數大多數情況下是移位和補最左邊的位 也就是補最高有效位 移幾位就補幾位,此時稱為算術右移。include using namespace std void main buf 1 temp 0x00ff temp temp 8...