**关于c移位操作的奇怪问题(高分征解)**

donghaish 2009-08-04 10:27:24
#include <stdio.h>
#include <iostream>
int main()
{
int a = 33;
long t1 = 1<<a;
long t2 = 1<<33;

printf("t1=%ld, t2=%ld.\n",t1, t2);
//printf("t1=%u, t2=%u.\n",(unsigned)1<<a, (unsigned)1<<32);

system("pause");
return 0;
}

这个程序在32-bit和64-bit机器上的运行结果都是是:t1=2, t2=0.
我认为t2=0合理,拿32-bit机举例子,int是32位,移33位都移没了,所以应该是0.
但运行的实际结果让人很难理解,都是移33位为啥结果大不一样?!
...全文
496 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
an060501076 2009-08-19
  • 打赏
  • 举报
回复
唔明...
wuhaiyangdh 2009-08-10
  • 打赏
  • 举报
回复
baihacker厉害
fly200124 2009-08-08
  • 打赏
  • 举报
回复
我在我的机器上使用VC 6.0进行编译后,发现怎么输出都是0,请帮忙说明下原因:
#include<stdio.h>
main()
{
int a = 33;
long t1 = 1 >> a;
long t2 = 1 >> 33;
printf("%ld,%ld\n",t1,t2);
}
怎么回事??
baihacker 2009-08-05
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 donghaish 的回复:]
我用的是%lld啊...

...
printf("%lld,%lld\n", t1, t2);
...
[/Quote]
嗯...本地输出是会有问题的...不用管...
donghaish 2009-08-05
  • 打赏
  • 举报
回复
我用的是%lld啊...

...
printf("%lld,%lld\n", t1, t2);
...
baihacker 2009-08-05
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 donghaish 的回复:]
to baihacker,
不知道我的理解对不对。
两个LL使得左移33位不会被截断,那为什么我用printf打印出的和被截断情况是一样的?
printf和cout打印的是同样的变量,变量结果一定是确定唯一的,但为什么输出不一样?
[/Quote]
要用%lld
Cricketol 2009-08-05
  • 打赏
  • 举报
回复
学习!!
donghaish 2009-08-05
  • 打赏
  • 举报
回复
to baihacker,
不知道我的理解对不对。
两个LL使得左移33位不会被截断,那为什么我用printf打印出的和被截断情况是一样的?
printf和cout打印的是同样的变量,变量结果一定是确定唯一的,但为什么输出不一样?
baihacker 2009-08-05
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 donghaish 的回复:]
引用 20 楼 baihacker 的回复:
我在五楼的说法,在intel cpu手册上木有,但是在INSTRUCTION SET REFERENCE上找到了说法:
Intel Architecture Compatibility
The 8086 does not mask the shift count. However, all other Intel Architecture processors
(starting with the Intel 286 processor) do mask the shift count to five bits, resulting in a
maximum count of 31. This masking is done in all operating modes (including the virtual-8086
mode) to reduce the maximum execution time of the instructions.

从286开始,位移量截取了低五位,也就是说最多位移31位,在所有模式下都适用.(貌似这里只是在说32位CPU)

也就是说,你里出现的行为是CPU对位移指令的实现所决定的,换一种就说不定老,如果用个C++解释器来解释,这也说不定了.


C/C++ codeint a=33;longlong t1= 1LL < <a;longlong t2= 1LL < <33;
std::cout < < t1 < <  std::endl < < t2 < < std::endl;

还可以试试这个


我试过你给的C++ code,我用printf和cout分别打印t1,t2,但结果不一样:
0,2
8589934592
8589934592

程序如下:
#include <stdio.h>
#include <iostream>

int main(void)
{
    int a = 33;
    long long t1 = 1LL < <a;
    long long t2 = 1LL < <33;
    printf("%lld,%lld\n", t1, t2);
std::cout < < t1 < <  std::endl < < t2 < < std::endl;


system("pause");
return 0;
}
现在又有些糊涂了,不论何种编译期,只要选定一种,其t1,t2的值应该是确定的,但为什么两个不同输出函数输出的结果不一样呢?
[/Quote]
注意两个LL
donghaish 2009-08-05
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 baihacker 的回复:]
我在五楼的说法,在intel cpu手册上木有,但是在INSTRUCTION SET REFERENCE上找到了说法:
Intel Architecture Compatibility
The 8086 does not mask the shift count. However, all other Intel Architecture processors
(starting with the Intel 286 processor) do mask the shift count to five bits, resulting in a
maximum count of 31. This masking is done in all operating modes (including the virtual-8086
mode) to reduce the maximum execution time of the instructions.

从286开始,位移量截取了低五位,也就是说最多位移31位,在所有模式下都适用.(貌似这里只是在说32位CPU)

也就是说,你里出现的行为是CPU对位移指令的实现所决定的,换一种就说不定老,如果用个C++解释器来解释,这也说不定了.


C/C++ codeint a=33;longlong t1= 1LL<<a;longlong t2= 1LL<<33;
std::cout<< t1<< std::endl<< t2<< std::endl;

还可以试试这个
[/Quote]

我试过你给的C++ code,我用printf和cout分别打印t1,t2,但结果不一样:
0,2
8589934592
8589934592

程序如下:
#include <stdio.h>
#include <iostream>

int main(void)
{
int a = 33;
long long t1 = 1LL <<a;
long long t2 = 1LL <<33;
printf("%lld,%lld\n", t1, t2);
std::cout << t1 << std::endl << t2 << std::endl;


system("pause");
return 0;
}
现在又有些糊涂了,不论何种编译期,只要选定一种,其t1,t2的值应该是确定的,但为什么两个不同输出函数输出的结果不一样呢?
donghaish 2009-08-05
  • 打赏
  • 举报
回复
to supermegaboy and ForestDB,
谢谢哈,你们从另一个角度阐释了这个问题,纠正了我的一个错误思维模式。:)

ForestDB,分已给了,不好意思哈。
另外,想多问一句:为什么“有时候想想,从电路的设计角度来看,这样做挺有意义的”,能不能解释一下:)
ForestDB 2009-08-05
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 baihacker 的回复:]
我在五楼的说法,在intel cpu手册上木有,但是在INSTRUCTION SET REFERENCE上找到了说法:
Intel Architecture Compatibility
The 8086 does not mask the shift count. However, all other Intel Architecture processors
(starting with the Intel 286 processor) do mask the shift count to five bits, resulting in a
maximum count of 31. This masking is done in all operating modes (including the virtual-8086
mode) to reduce the maximum execution time of the instructions.

从286开始,位移量截取了低五位,也就是说最多位移31位,在所有模式下都适用.(貌似这里只是在说32位CPU)

也就是说,你里出现的行为是CPU对位移指令的实现所决定的,换一种就说不定老,如果用个C++解释器来解释,这也说不定了.


C/C++ codeint a=33;longlong t1= 1LL<<a;longlong t2= 1LL<<33;
std::cout<< t1<< std::endl<< t2<< std::endl;

还可以试试这个
[/Quote]
另外的确是有这个说法,我原来也为了解决这个问题特地查了下x86指令参考手册,手册上是提到的这样一个词
'five bit mask',有时候想想,从电路的设计角度来看,这样做挺有意义的。
ForestDB 2009-08-05
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 supermegaboy 的回复:]
还有你不要拿编译器的结果当答案,编译器只是标准的一个实现而已,你可以用它来验证,但不是答案,否则就是本末倒置了。
[/Quote]
这个说法的确是很有道理,不过干这行久了,有个说法叫事实上的标准。
其实我还是很爱拿汇编说事,因为就算是标准,一时半会找不到那种可以验证反例的编译器,有时候还是很难有说服力。
而我一般都会提及这是在xx平台下,用的xx编译器的结果,不过一般xx大家都一样,有时候就忘提了。
zhouzhipen 2009-08-05
  • 打赏
  • 举报
回复
这和32位机还是64位机有什么关系?你的编译器就32位的.下面的这两个变量都是被编译成32位的了.
long t1 = 1 < <a;
long t2 = 1 < <33;

结果之所以会这样,第一个1 < <a是到运行程序时才计算,33位,过了一个所以是0.
第二个,1 < <33,两个都是常数,编译器会在编译程序时就帮你计算了,编译成类似t2 = 2,
至于为什么会是2,这不同的编译器有不同的处理方法,不同的编译器结果可能都不同.
donghaish 2009-08-05
  • 打赏
  • 举报
回复
谢谢大家,学到了不少东西。给分了.:)
baihacker 2009-08-05
  • 打赏
  • 举报
回复
我在五楼的说法,在intel cpu手册上木有,但是在INSTRUCTION SET REFERENCE上找到了说法:
Intel Architecture Compatibility
The 8086 does not mask the shift count. However, all other Intel Architecture processors
(starting with the Intel 286 processor) do mask the shift count to five bits, resulting in a
maximum count of 31. This masking is done in all operating modes (including the virtual-8086
mode) to reduce the maximum execution time of the instructions.

从286开始,位移量截取了低五位,也就是说最多位移31位,在所有模式下都适用.(貌似这里只是在说32位CPU)

也就是说,你里出现的行为是CPU对位移指令的实现所决定的,换一种就说不定老,如果用个C++解释器来解释,这也说不定了.


    int a = 33; 
long long t1 = 1LL <<a;
long long t2 = 1LL <<33;
std::cout << t1 << std::endl << t2 << std::endl;


还可以试试这个
科技完美生活 2009-08-05
  • 打赏
  • 举报
回复
前来学习
baihacker 2009-08-05
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 mu_yang 的回复:]
引用 15 楼 supermegaboy 的回复:
还有你不要拿编译器的结果当答案,编译器只是标准的一个实现而已,你可以用它来验证,但不是答案,否则就是本末倒置了。


这句应该在本论坛置顶。
用编译后的汇编指令来解释C语言可以休矣!
[/Quote]
现在还经常见到这样的...用汇编来解释...
mu_yang 2009-08-05
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 supermegaboy 的回复:]
还有你不要拿编译器的结果当答案,编译器只是标准的一个实现而已,你可以用它来验证,但不是答案,否则就是本末倒置了。
[/Quote]

这句应该在本论坛置顶。
用编译后的汇编指令来解释C语言可以休矣!
donghaish 2009-08-05
  • 打赏
  • 举报
回复
好的,谢谢
加载更多回复(16)

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧