我们可以在 while 循环中左移一个值吗?

Can we left shift a value inside a while loop?

我尝试使用左移来使用计数器识别设置位。当我尝试左移 var 时,我发现它陷入了无限循环并且只打印了零。 以下代码有什么问题?在 while 循环中使用左移是否合法?

#include <stdio.h>
#include <limits.h>
int main(int argc, char **argv)
{
    int var =1;

    while(var<INT_MAX)
    {   
        var = var<<1;
        printf("%d\n", var);        
    }

    return 0;
}

在这个循环中

while(var<INT_MAX)
{   
    var = var<<1;
    printf("%d\n", var);        
}

var 永远不能等于 INT_MAX 因为它只设置了一位

int 变量 =1;

即移位。

尝试以下循环:

while(var<INT_MAX)
{   
    var = ( var << 1 ) + 1;
    printf("%d\n", var);        
} 

这是一个演示程序,为了简单起见,使用了有符号类型 signed char,而不是有符号类型 int。

#include <stdio.h>
#include <limits.h>

int main(void) 
{
    signed char var = 1;

    while ( var  < SCHAR_MAX )
    {   
        var = ( var << 1 )  + 1;
        printf( "%d\n",  var );        
    }

    return 0;
}

程序输出为

3
7
15
31
63
127

并且根据 C 标准(5.2.4.2.1 整数类型的大小 <limits.h>

— maximum value for an object of type signed char
SCHAR_MAX +127 // 2^7 − 1

在循环中使用移位操作非常好。 您的代码的问题是 var 永远不会等于或大于 INT_MAX.

为了更好地理解,让我解释一下 8 位有符号整数而不是 32 位有符号整数的问题。

您从值 var = 00000001b 开始(b 表示它是一个二进制数),8 位有符号整数的 INT_MAX 将是 INT_MAX = 01111111b = 127 (注意最高位是0,这是因为是符号位)

现在,如果你向左移动 var,你就会将这个 1 缓慢地向右移动

var << 1 = 00000010b =    2
var << 2 = 00000100b =    4
var << 3 = 00001000b =    8
var << 4 = 00010000b =   16
var << 5 = 00100000b =   32
var << 6 = 01000000b =   64
var << 7 = 10000000b = -128
var << 8 = 00000000b =    0
var << 9 = 00000000b =    0
...

第七次移位后,1 位达到最高位,但由于我们有一个 8 位有符号整数,我们将 10000000b 解释为 128,而不是 -128,因此 var < INT_MAX 永远是真的。

如果您不知道为什么会发生这种情况,您可能需要阅读 two complement 个数字。

编辑: 更正式地说,就像 Andrew Henle 指出的那样:将一个值移出其类型的范围是没有定义的。 操作 x << y 的结果必须等于 x * 2^y 并且如果 x * 2 ^y 未用类型表示 table,则结果未定义。

所以上面的 table 看起来更像

var << 1 = 00000010b =      2
var << 2 = 00000100b =      4
var << 3 = 00001000b =      8
var << 4 = 00010000b =     16
var << 5 = 00100000b =     32
var << 6 = 01000000b =     64
var << 7 = undef.    = undef.
var << 8 = undef.    = undef.
var << 9 = undef.    = undef.
...