我们可以在 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.
...
我尝试使用左移来使用计数器识别设置位。当我尝试左移 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.
...