zoukankan      html  css  js  c++  java
  • C/C++移位运算符出界后的结果是不可预期的

    以前看到C++标准上说,移位运算符(<<、>>)出界时的行为并不确定:

    The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.

    我当时也没有深究过这个问题。前几天有个网友来信问起这件事,我才发现,这和Intel CPU的移位运算有关。下面是那位网友的来信以及我的回复:


    您好!运算符<<作为位操作中的高效的操作,但我遇到一个问题:下面在VC环境下发现一个很不明白的地方,下面标注。

    #include <stdio.h>
    void main()
    {
       unsigned int i,j;
       i=35;

       //为什么下面两个左移操作结果不一样?
       j=1<<i;  // j为8
       j=1<<35; // j为0
    }

    不知是哪里没有理解对。


    原因是这样的:i=35;j=1<<i;这两句在VC没有做优化的情况下,将被编译成下面的机器指令:

    mov dword ptr [i],23h
    mov eax,1
    mov ecx,dword ptr [i]
    shl eax,cl
    mov dword ptr [j],eax

    在shl一句中,eax=1,cl=35。而Intel CPU执行shl指令时,会先将cl与31进行and操作,以限制左移的次数小于等于31。因为35 & 31 = 3,所以这样的指令相当于将1左移3位,结果是8。

    而j=1<<35;一句是常数运算,VC即使不做优化,编译器也会直接计算1<<35的结果。VC编译器发现35大于31时,就会直接将结果设置为0。这行代码编译产生的机器指令是:

    mov dword ptr [j],0

    对上面这两种情况,如果把VC编译器的优化开关打开(比如编译成Release版本),编译器都会直接将结果设置为0。

    所以,在C/C++语言中,移位操作不要超过界限,否则,结果是不可预期的。

    下面是Intel文档中关于shl指令限制移位次数的说明:

    The destination operand can be a register or a memory location. The count operand can be an immediate value or register CL. The count is masked to 5 bits, which limits the count range to 0 to 31. A special opcode encoding is provided for a count of 1.

  • 相关阅读:
    26 转义符 re模块 方法 random模块 collection模块的Counter方法
    25 正则表达式
    24 from 模块 import 名字
    24 from 模块 import 名字
    24 from 模块 import 名字
    23 析构方法 items系列 hash方法 eq方法
    21 isinstance issubclass 反射 _str_ _new_ _len_ _call_
    20 属性, 类方法, 静态方法. python2与python3的区别.
    python(1)
    python之字符串格式化
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157278.html
Copyright © 2011-2022 走看看