发新话题
打印

【讨论】-1 左移 32 位结果还是 -1?

不过,我用objdump出的和gcc -S出的不一样?      
上帝说,有问题,找GOOGLE 写程序是很神圣的事情!同样只是装系统,卖菜的大娘会的事情不见得就跟卖菜一样了。

TOP

看了看 80386 的指令系统, 有这么一段话:
The [B]8086 does not mask the shift count[/B]. However, [B]all other[/B] Intel Architecture processors (starting with the Intel 286 processor) do mask the shift count to [B]5 bits[/B], resulting in a maximum count of 31. This masking is done in all operating modes (including the virtual-8086 mode) [B]to reduce the maximum execution time of the instructions[/B].
      
'
梅须逊雪三分白 雪却输梅一段香

TOP

[QUOTE=DarkSpy]32 位的机器上, 左移或者右移 32 bit 编译器将会做取模运算,然后再次移动, 所以左移和右移 32bit 是没有意义的...[/QUOTE]
5 W& ?( F. Q* ]3 \$ u" e
- ?0 X" \2 I3 g" ^0 r! q习惯性说编译器了,说错了.
# r$ o) p; J6 Z9 I0 H% Z应该是硬件的做法      
-----------------------------------------
http://www.darkspy.org/blog

自大的人把宗教当迷信,无知的人把迷信当宗教

TOP

-1用补吗表示就是11111111111111111111111111111111,左移当然还是-1了。      
白金之心

TOP

-1<<n汇编出来的是
! E9 Y6 ^- F7 [8 h        movl    $-1, %eax% s1 k$ {! ~8 ~' L8 d; w
        sall    %cl, %eax( V/ J" B& p; |1 J6 c6 l
4 b( e( Z9 N5 k9 v, s- W. R% g, N- c
如果是逻辑左移的话就是0
( c# K$ x8 {' x     即:9 I& s* a% z' ]/ R/ a
         movl    $-1, %eax: A0 b6 r1 S# P. X
        shll    %cl, %eax
" a7 m( x+ \6 f) ~没有什么怪的,这时gcc 的处理,看一下汇编就知道了      

TOP

高人高见       
'
梅须逊雪三分白 雪却输梅一段香

TOP

[QUOTE=sof_ljh]-1<<n汇编出来的是: I( {& Q, d# s& g3 A, u9 {0 {
        movl    $-1, %eax
8 g- s, Q+ L6 u2 D        sall    %cl, %eax
# z& J+ J' }0 P) ?# y' M6 g# j% K( @
如果是逻辑左移的话就是0% z0 y/ Z, x+ K5 K% N6 x( f- Z$ x$ ~
     即:
4 @  E: V/ H) a' t; R( i) V         movl    $-1, %eax
% E+ g! `% N5 Y+ a3 h        shll    %cl, %eax( t5 Q6 @. C, s! W1 ^6 T) K. _
没有什么怪的,这时gcc 的处理,看一下汇编就知道了[/QUOTE]& X+ `/ D) ~: u2 [7 e" j

6 b$ I4 j# F. w! }! s: X! R, n好像你自己没有仔细看汇编书啊。
! J, X9 U" H" l7 f. X
' Y; K) S, N. d' J' ~+ D汇编指令 sal 和 shl 是完全等价的,它们只是助记符不同罢了,其操作码完全一样。因此算术左移和逻辑左移是一样的。移位以后,都是用 0 填充腾空的位。
/ u$ t8 N3 y$ j% X' e4 U
. h# O# g; g# S+ x  c& Q只有算术右移和逻辑右移才是不同的。算术右移用符号位填补腾空的位,逻辑右移用 0 填补腾空位。7 \! J, I# _& e1 K  b& n' c
6 Z- ~$ ^" W5 e9 R: R
前面有人已经解释得很清楚了,-1 左移32位,对于 386 以后的CPU来说,就是左移 0 位(假定是在运行期间由机器的 CPU 来执行 sal %cl, %eax 或者等价的 shl %cl, %eax),当然不变了。+ q2 L. Y- i( J6 J

" h3 N8 m8 ~( ]+ \+ N如果用常量表达式 -1 << 32 ,那么编译器会计算出这是一个 0。
/ |- X3 o& x1 {, S6 E6 G1 h1 K$ F4 q0 ?0 H- v
另外个人认为, 386 以后的硬件把移位对字长进行取模的做法,没有利,只有弊。还是 -1 左移 32 位之后变成 0 比较合理。      
渴望春天 come, sweet May!

TOP

[QUOTE=yangkwch]-1用补吗表示就是11111111111111111111111111111111,左移当然还是-1了。[/QUOTE]
6 u4 O  P" u* }5 r3 {- m; a' c( b$ ]; Y
显然这个解释是不对的。
6 x. r& `6 g0 |. w
% K/ I& M) U  C6 t$ I" a1 j' X* [按照这个逻辑,-1 左移 1 位仍然是  -1 了。这肯定不对吧?
; o6 s3 a0 H7 t
# B* t$ |* u9 H9 w左移之后,腾空的位是用 0 来填充的,因此,如果不是左移了 0 位,-1 左移之后就不会等于 -1 了。
$ G5 R& o) i# n/ n/ @: m3 R# e, I" z9 V
前面有人已经解释了,左移 32 位正好就是左移了 0 位(CPU 把左移的位数 32 对于字长 32 进行取模运算,得到 0),因此 -1 左移 32 位仍然是 -1。0 x. t7 q' d5 p/ }$ [

- c/ x# e2 X' g另外,-1 循环左移或者循环右移任意位,仍然是 -1,这是正确的。**移位** 和 **循环移位** 是不同的汇编指令。C 语言中的移位(就是 “<<” 和 “>>”)大概都编译成汇编的“移位”了,不生成汇编的“循环移位”。8 y$ n# T' \7 Y) f2 _/ ^

* w3 ?% U0 D8 X其实在汇编中,循环移位又分为带进位的和不带进位的两种。刚才说的 -1 循环左移或者循环右移任意位,仍然是 -1,其实是对不带进位的循环移位指令来说的。而对于带进位的循环指令,“-1 循环左移或者循环右移任意位,仍然是 -1” 这句话也是不能普遍成立的(如果再加上进位标志 CF=1 这个条件,就成立了)。      
渴望春天 come, sweet May!

TOP

good       
'
梅须逊雪三分白 雪却输梅一段香

TOP

这个帖子似乎应该是了结了,虽然楼上说看汇编代码能够明白了。- A) Y. f1 J. ^4 ~
不过我还是想灌次水。( \% R2 n+ T4 v8 w& {
! ?5 V9 }0 o, B- {
这是C99标准里
" t$ m6 O8 s$ n: E 6.5.7 Bitwise shift operators" w6 J4 n! x7 m
一节中提到的:
& ?! l5 Z# ?; J! ~, N Semantics5 W8 d$ H% ~' i( x) {7 {
     ……
0 ~( ?9 s: R, n1 O% [+ s) y 4 The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with
8 l0 _8 Q2 K& a7 L7 L% F* c1 K   zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2 , reduced modulo
0 U' R  q+ ?. a   one more than the maximum value representable in the result type. If E1 has a signed4 N% m. U) \, Y
   type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is
  @/ i7 s6 M* Y. @5 D, m2 p- e' d9 U 4 d. H+ J% k" C% _0 X6 \2 D. p
在GCC参考手册
' b( J$ m1 J8 E7 P4 f" h 4.5 Integers (Page 207)有这样一段话:
. F/ m* T+ _) i2 T! A3 h
2 H: _- ], x$ E" X • The results of some bitwise operations on signed integers (C90 6.3, C99 6.5).
$ m/ h) Q/ J+ ]: `3 R- c   Bitwise operators act on the representation of the value including both the sign and
+ H2 b7 _/ m  |. a- Z' U5 [   value bits, where the sign bit is considered immediately above the highest-value value& B* B  f# W# W% `: S
   bit. Signed ‘>>’ acts on negative numbers by sign extension.9 A4 J* X1 m! {* u! E( q8 d
   GCC does not use the latitude given in C99 only to treat certain aspects of signed ‘<<’
( |, z5 T% p) c' B1 l0 S2 |4 X9 ^0 J   as undefined, but this is subject to change.# {6 s/ p7 _, P- e& ~& h* o) G
( y$ ]( l2 k% ]: H$ t, f
我不想翻译,很容易理解,我不知道版主讨论这个是不是因为GCC没有遵循标准,还是其他什么原因引来一群人的争吵?
* D" A2 Z/ {$ X5 W( y 另外,我也想顺便问下,(但我不想发新帖了)为什么我的编译器汇编后的代码总是比别人的长,是不是被SUSE修改过的GCC版本。
- X2 j0 L6 \" H; m 我用的是SUSE自带的GCC,比如上面的汇编代码,在我机器中出来的是
复制内容到剪贴板
代码:
BirdSky:/home/souldump/bin # gcc -S main.c
main.c:10:2: warning: no newline at end of file
BirdSky:/home/souldump/bin # cat main.s
         .file   "main.c"
         .section        .rodata
.LC0:
         .string "%d\n"
         .text
.globl main
         .type   main, @function
main:
         leal    4(%esp), %ecx
         andl    $-16, %esp
         pushl   -4(%ecx)
         pushl   %ebp
         movl    %esp, %ebp
         pushl   %ecx
         subl    $36, %esp
         movl    $32, -8(%ebp)
         movl    -8(%ebp), %ecx
         movl    $-1, %eax
         sall    %cl, %eax
         movl    %eax, 4(%esp)
         movl    $.LC0, (%esp)
         call    printf
         movl    $0, %eax
         addl    $36, %esp
         popl    %ecx
         popl    %ebp
         leal    -4(%ecx), %esp
         ret
         .size   main, .-main
         .ident  "GCC: (GNU) 4.1.0 (SUSE Linux)"
         .section        .note.GNU-stack,"",@progbits
长了好多,很多次用自己的汇编代码和别人的比较都会长一些。      

TOP

发新话题