荔园在线
荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀
[回到开始]
[上一篇][下一篇]
发信人: huhaiming (一生只爱她), 信区: Program
标 题: [合集]发现一个很奇怪的C的语法
发信站: 荔园晨风BBS站 (Fri Apr 30 18:33:04 2004), 站内信件
tec (TO BE A BETTER MAN!) 于Mon Mar 1 12:22:46 2004提到:
#include <stdio.h>
void main()
{
int one = 1;
printf("%d\n", (int)(1<<31));
printf("%d\n", (int)(one<<31));
printf("%d\n", (int)(1<<32));
printf("%d\n", (int)(one<<32));
printf("%d\n", (int)(1<<33));
printf("%d\n", (int)(one<<33));
printf("\n");
}
这个程序在VC下运行结果为:
-2147483648
-2147483648
0
1
0
2
在TC下也有类似的输出:
0
0
0
1
0
2
是不是很奇怪??
bigone (低音穿过我的耳) 于Mon Mar 1 12:40:45 2004提到:
<< 是什么意思啊?
Jialand (dynamic devoting) 于Mon Mar 1 12:42:03 2004提到:
左移?
tec (TO BE A BETTER MAN!) 于Mon Mar 1 12:47:11 2004提到:
对阿
tec (TO BE A BETTER MAN!) 于Mon Mar 1 12:49:50 2004提到:
你不是忘得这么快吧?:)
jjk (base) 于Mon Mar 1 13:45:49 2004提到:
有warning的, 越界了.
# gcc -Wall -o strange strange.c
strange.c:4: warning: return type of `main' is not `int'
strange.c: In function `main':
strange.c:10: warning: left shift count >= width of type
strange.c:11: warning: left shift count >= width of type
strange.c:13: warning: left shift count >= width of type
strange.c:14: warning: left shift count >= width of type
michaelx (Silver Bullet) 于Mon Mar 1 13:51:01 2004提到:
这个当然有,不然怎么会有负数出现
littlebao (爱拼才会赢) 于Mon Mar 1 15:12:42 2004提到:
应该是对常量进行了左移操作,所以移了32位后为0了
而对变量在四个字节内进行了循环左移
MFC (大四,差不多毕业了!) 于Mon Mar 1 16:35:27 2004提到:
VC是32位编译器,左移了31位,1到了最位,而在
二进制中,机器数的最高位为符号位,0表示正数,
1表示负数.故出现了负数.
littlebao (爱拼才会赢) 于Mon Mar 1 16:46:08 2004提到:
这个并不是编译器的问题,而是用int做了转换
int是4个字节即32位,如果用char只有8位
MFC (大四,差不多毕业了!) 于Mon Mar 1 16:58:59 2004提到:
但是如果你不用int做转换,结果也是一样的,
如果是int问题,怎么解释在VC与TC结果不同呢?
tec (TO BE A BETTER MAN!) 于Mon Mar 1 17:21:47 2004提到:
应该不是循环左移,因为int two = 2; two<<31是0而不是1,
我想可能是对变量而言,<<右边的参数要对左边参数位数取模,
而对常量而言则不用。
littlebao (爱拼才会赢) 于Mon Mar 1 17:32:57 2004提到:
从以下程序的结果看应该是循环左移的
void main()
{
int one = 1;
for(int i = 0 ; i < 64 ; ++i)
printf("%d\n" , (int)(one << i)) ;
}
? 在 tec (TO BE A BETTER MAN!) 的大作中提到: 】
tec (TO BE A BETTER MAN!) 于Mon Mar 1 17:38:43 2004提到:
~~ 是因为1的关系,你换256看看
tec (TO BE A BETTER MAN!) 于Mon Mar 1 18:05:28 2004提到:
这里错了,是固定对32取模的,我试过了
而且网上有人说C#也采取这种规则的
jjksam (base) 于Mon Mar 1 18:43:00 2004提到:
是算术左移。
#include <stdio.h>
int main()
{
int one=1;
printf("%d\n", (int)(one<<31));
return 0;
}
jjksam (base) 于Mon Mar 1 18:46:28 2004提到:
VC 6.0反汇编:
1: #include <stdio.h>
2:
3: int main()
4: {
00401010 push ebp
00401011 mov ebp,esp
00401013 sub esp,44h
00401016 push ebx
00401017 push esi
00401018 push edi
00401019 lea edi,[ebp-44h]
0040101C mov ecx,11h
00401021 mov eax,0CCCCCCCCh
00401026 rep stos dword ptr [edi]
5: int one=1;
00401028 mov dword ptr [ebp-4],1
6: printf("%d\n", (int)(one<<31));
0040102F mov eax,dword ptr [ebp-4]
00401032 shl eax,1Fh
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~逻辑左移
00401035 push eax
00401036 push offset string "%d\n" (0042001c)
0040103B call printf (00401070)
00401040 add esp,8
7: return 0;
00401043 xor eax,eax
8: }
00401045 pop edi
00401046 pop esi
00401047 pop ebx
00401048 add esp,44h
0040104B cmp ebp,esp
0040104D call __chkesp (004010f0)
00401052 mov esp,ebp
00401054 pop ebp
00401055 ret
jjksam (base) 于Mon Mar 1 18:57:01 2004提到:
6: printf("%d\n", (int)(one<<31));
0040B77F mov eax,dword ptr [ebp-4]
0040B782 shl eax,1Fh
0040B785 push eax
0040B786 push offset string "%d\n" (0042001c)
0040B78B call printf (00401070)
0040B790 add esp,8
7: printf("%d\n", (int)(one<<32));
0040B793 mov ecx,dword ptr [ebp-4]
0040B796 shl ecx,20h
0040B799 push ecx
0040B79A push offset string "%d\n" (0042001c)
0040B79F call printf (00401070)
0040B7A4 add esp,8
8: printf("%d\n", (int)(one<<33));
0040B7A7 mov edx,dword ptr [ebp-4]
0040B7AA shl edx,21h
~~~~~~~~~这里并没有取模哦。。
0040B7AD push edx
0040B7AE push offset string "%d\n" (0042001c)
0040B7B3 call printf (00401070)
0040B7B8 add esp,8
9: return 0;
0040B7BB xor eax,eax
这里错了,是固定对32取模的,我试过了
而且网上有人说C#也采取这种规则的
jjksam (base) 于Mon Mar 1 19:02:13 2004提到:
对常量这样做左移操作的话,编译器会自动帮你优化成一个数的,gcc和VC的编译器都
会这样
我只贴gcc的了
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
movl $1, -4(%ebp)
subl $8, %esp
pushl $-2147483648
~~~~~~~~~~~~~~~~~~~~~~~~``
pushl $.LC0
call printf
addl $16, %esp
subl $8, %esp
pushl $0
`~~~~~~~~~~~~~~~~变成0了
pushl $.LC0
call printf
addl $16, %esp
subl $8, %esp
pushl $0
~~~~~~~~~~~~~~~~~~~~~~变成0了
pushl $.LC0
call printf
addl $16, %esp
movl $0, %eax
leave
ret
bachelor (bachelor) 于Mon Mar 1 20:14:06 2004提到:
这有什么奇怪的,很明显是对编译器的边界测试。
tec (TO BE A BETTER MAN!) 于Wed Mar 3 22:05:30 2004提到:
从这两个贴来看就应该是shl指令已经包含对移位数取模的操作了,
这也难怪对所有类型的左操作数都是对32取模的
tec (TO BE A BETTER MAN!) 于Wed Mar 3 22:08:40 2004提到:
这个我也想过,不过没反汇编看过,这点还是你比较醒^_^
编译器对算术左移和CPU 指令的理解不一样,呵呵
jjksam (base) 于Wed Mar 3 22:29:59 2004提到:
可以再深入研究,这个就要看Intel的指令集了,要看它的实现是怎样的。
tec (TO BE A BETTER MAN!) 于Wed Mar 3 22:38:07 2004提到:
钻不了那么深阿,我还是写我的game算了,哈哈
tec (TO BE A BETTER MAN!) 于Thu Mar 4 19:47:55 2004提到:
编译器对左移操作的理解和硬件指令的不同亚,所以还是奇怪
这个我也想过,不过没反汇编看过,这点还是你比较醒^_^
编译器对算术左移和CPU 指令的理解不一样,呵呵
jjksam (base) 于Wed Mar 3 22:29:59 2004提到:
可以再深入研究,这个就要看Intel的指令集了,要看它的实现是怎样的。
tec (TO BE A BETTER MAN!) 于Wed Mar 3 22:38:07 2004提到:
钻不了那么深阿,我还是写我的game算了,哈哈
tec (TO BE A BETTER MAN!) 于Thu Mar 4 19:47:55 2004提到:
编译器对左移操作的理解和硬件指令的不同亚,所以还是奇怪
[回到开始]
[上一篇][下一篇]
荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店