user-0 提问: 别运行，写结果

回复:
user: user-0
content: 引用 26 楼 ForestDB 的回复:32 > 31 x86下基本按>> 0处理了 可以去看x86指令集 shift right指令有个32的mask 意思是只要是基于X86架构的系统下不管哪个编译器，都会处理为移0位么？

user: user-1
content: 我以前用BYTE测试过  直接被转换为int来处理了

user: user-2
content: 如果第一个操作数为 int 或 uint（32 位数），则移位数由第二个操作数的低五位给出（第二个操作数 & 0x1f）。

user: user-3
content: SAL/SAR/SHL/SHR—Shift INSTRUCTION SET REFERENCE, M-Z 4-398 Vol. 2B  Instruction Operand Encoding Description Shifts the bits in the first operand (destination operand) to the left or right by the number of bits specified in the second operand (count operand). Bits shifted beyond the destination operand boundary are first shifted into the CF flag, then discarded. At the end of the shift operation, the CF flag contains the last bit shifted out of the destination operand. The destination operand can be a register or a memory location. The count operand can be an immediate value or the CL register. The count is masked to 5 bits (or 6 bits if in 64-bit mode and REX.W is used). The count range is limited to 0 to 31 (or 63 if 64-bit mode and REX.W is used). A special opcode encoding is provided for a count of 1. The shift arithmetic left (SAL) and shift logical left (SHL) instructions perform the same operation; they shift the bits in the destination operand to the left (toward more significant bit locations). For each shift count, the most significant bit of the destination operand is shifted into the CF flag, and the least significant bit is cleared (see Figure 7-7 in the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1). Opcode Instruction Op/ En 64-Bit Mode Compat/ Leg Mode Description REX.W + D1 /4 SHL r/m64,1 M1 Valid N.E. Multiply r/m64 by 2, once. D3 /4 SHL r/m32, CL MC Valid Valid Multiply r/m32 by 2, CL times. REX.W + D3 /4 SHL r/m64, CL MC Valid N.E. Multiply r/m64 by 2, CL times. C1 /4 ib SHL r/m32, imm8 MI Valid Valid Multiply r/m32 by 2, imm8 times. REX.W + C1 /4 ib SHL r/m64, imm8 MI Valid N.E. Multiply r/m64 by 2, imm8 times. D0 /5 SHR r/m8,1 M1 Valid Valid Unsigned divide r/m8 by 2, once. REX + D0 /5 SHR r/m8**, 1 M1 Valid N.E. Unsigned divide r/m8 by 2, once. D2 /5 SHR r/m8, CL MC Valid Valid Unsigned divide r/m8 by 2, CL times. REX + D2 /5 SHR r/m8**, CL MC Valid N.E. Unsigned divide r/m8 by 2, CL times. C0 /5 ib SHR r/m8, imm8 MI Valid Valid Unsigned divide r/m8 by 2, imm8 times. REX + C0 /5 ib SHR r/m8**, imm8 MI Valid N.E. Unsigned divide r/m8 by 2, imm8 times. D1 /5 SHR r/m16, 1 M1 Valid Valid Unsigned divide r/m16 by 2, once. D3 /5 SHR r/m16, CL MC Valid Valid Unsigned divide r/m16 by 2, CL times C1 /5 ib SHR r/m16, imm8 MI Valid Valid Unsigned divide r/m16 by 2, imm8 times. D1 /5 SHR r/m32, 1 M1 Valid Valid Unsigned divide r/m32 by 2, once. REX.W + D1 /5 SHR r/m64, 1 M1 Valid N.E. Unsigned divide r/m64 by 2, once. D3 /5 SHR r/m32, CL MC Valid Valid Unsigned divide r/m32 by 2, CL times. REX.W + D3 /5 SHR r/m64, CL MC Valid N.E. Unsigned divide r/m64 by 2, CL times. C1 /5 ib SHR r/m32, imm8 MI Valid Valid Unsigned divide r/m32 by 2, imm8 times. REX.W + C1 /5 ib SHR r/m64, imm8 MI Valid N.E. Unsigned divide r/m64 by 2, imm8 times. NOTES: * Not the same form of division as IDIV; rounding is toward negative infinity. ** In 64-bit mode, r/m8 can not be encoded to access the following byte registers if a REX prefix is used: AH, BH, CH, DH. ***See IA-32 Architecture Compatibility section below. Op/En Operand 1 Operand 2 Operand 3 Operand 4 M1 ModRM:r/m (r, w) 1 NA NA MC ModRM:r/m (r, w) CL NA NA MI ModRM:r/m (r, w) imm8 NA NA SAL/SAR/SHL/SHR—Shift INSTRUCTION SET REFERENCE, M-Z Vol. 2B 4-399 The shift arithmetic right (SAR) and shift logical right (SHR) instructions shift the bits of the destination operand to the right (toward less significant bit locations). For each shift count, the least significant bit of the destination operand is shifted into the CF flag, and the most significant bit is either set or cleared depending on the instruction type. The SHR instruction clears the most significant bit (see Figure 7-8 in the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1); the SAR instruction sets or clears the most significant bit to correspond to the sign (most significant bit) of the original value in the destination operand. In effect, the SAR instruction fills the empty bit position’s shifted value with the sign of the unshifted value (see Figure 7-9 in the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1). The SAR and SHR instructions can be used to perform signed or unsigned division, respectively, of the destination operand by powers of 2. For example, using the SAR instruction to shift a signed integer 1 bit to the right divides the value by 2. Using the SAR instruction to perform a division operation does not produce the same result as the IDIV instruction. The quotient from the IDIV instruction is rounded toward zero, whereas the “quotient” of the SAR instruction is rounded toward negative infinity. This difference is apparent only for negative numbers. For example, when the IDIV instruction is used to divide -9 by 4, the result is -2 with a remainder of -1. If the SAR instruction is used to shift -9 right by two bits, the result is -3 and the “remainder” is +3; however, the SAR instruction stores only the most significant bit of the remainder (in the CF flag). The OF flag is affected only on 1-bit shifts. For left shifts, the OF flag is set to 0 if the most-significant bit of the result is the same as the CF flag (that is, the top two bits of the original operand were the same); otherwise, it is set to 1. For the SAR instruction, the OF flag is cleared for all 1-bit shifts. For the SHR instruction, the OF flag is set to the most-significant bit of the original operand. In 64-bit mode, the instruction’s default operation size is 32 bits and the mask width for CL is 5 bits. Using a REX prefix in the form of REX.R permits access to additional registers (R8-R15). Using a REX prefix in the form of REX.W promotes operation to 64-bits and sets the mask width for CL to 6 bits. See the summary chart at the beginning of this section for encoding data and limits. IA-32 Architecture Compatibility The 8086 does not mask the shift count. However, all other IA-32 processors (starting with the Intel 286 processor) do mask the shift count to 5 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. Operation IF 64-Bit Mode and using REX.W THEN countMASK ← 3FH; ELSE countMASK ← 1FH; FI tempCOUNT ← (COUNT AND countMASK); tempDEST ← DEST; WHILE (tempCOUNT ≠ 0) DO IF instruction is SAL or SHL THEN CF ← MSB(DEST); ELSE (* Instruction is SAR or SHR *) CF ← LSB(DEST); FI; IF instruction is SAL or SHL THEN DEST ← DEST ∗ 2; ELSE SAL/SAR/SHL/SHR—Shift INSTRUCTION SET REFERENCE, M-Z 4-400 Vol. 2B IF instruction is SAR THEN DEST ← DEST / 2; (* Signed divide, rounding toward negative infinity *) ELSE (* Instruction is SHR *) DEST ← DEST / 2 ; (* Unsigned divide *) FI; FI; tempCOUNT ← tempCOUNT – 1; OD; (* Determine overflow for the various instructions *) IF (COUNT and countMASK) = 1 THEN IF instruction is SAL or SHL THEN OF ← MSB(DEST) XOR CF; ELSE IF instruction is SAR THEN OF ← 0; ELSE (* Instruction is SHR *) OF ← MSB(tempDEST); FI; FI; ELSE IF (COUNT AND countMASK) = 0 THEN All flags unchanged; ELSE (* COUNT not 1 or 0 *) OF ← undefined; FI; FI; Flags Affected The CF flag contains the value of the last bit shifted out of the destination operand; it is undefined for SHL and SHR instructions where the count is greater than or equal to the size (in bits) of the destination operand. The OF flag is affected only for 1-bit shifts (see “Description” above); otherwise, it is undefined. The SF, ZF, and PF flags are set according to the result. If the count is 0, the flags are not affected. For a non-zero count, the AF flag is undefined.

user: user-4
content: 引用 25 楼 N_sev7 的回复:其实本来想移31位，判断符号位是否大于0  结果不管怎么运行都是大于0, 这里没看懂... 我vc6情况很正确啊...

user: user-3
content: 32 > 31 x86下基本按>> 0处理了 可以去看x86指令集 shift right指令有个32的mask

user: user-0
content: 引用 22 楼 CCDDzclxy 的回复:我想知道，lz是在何种情况下遇到这个坑的？我正常些代码，根本不会全移掉啊，清零的话，与或一下也行啊，是个什么样的思路？？ 想a>>NumShift;NumShift这个参数经过一些列的参数传递之后一个地方的值为32，其实本来想移31位，判断符号位是否大于0  结果不管怎么运行都是大于0,...因为a>>32位之后的数还是a 不过正像楼上很大大牛说的，这应该是一种未定义的行为，在不同的系统环境和编译环境下的结果是不一样的

user: user-5
content: 他还真是个坑，VC6 是0 VC9，VC10是256 估计，要么是新表准做了改动，要么就是未定义的。

user: user-5
content: 这和实现有关，如果编译器认为 移位和除以2等价，就会算作 0 ，否则直接在生成对应的移位指令。 那就可能不移位。 也许新标准就是不移位。

user: user-3
content: 引用 31 楼 N_sev7 的回复:[quote=引用 26 楼 ForestDB 的回复:] 32 > 31 x86下基本按>> 0处理了 可以去看x86指令集 shift right指令有个32的mask 意思是只要是基于X86架构的系统下不管哪个编译器，都会处理为移0位么？[/quote] 看28L  这个得看编译器的行为 如果编译器将>>翻译成了shitf指令，那么shift指令的行为就是这样的了。

user: user-0
content: 引用 27 楼 CCDDzclxy 的回复:[quote=引用 25 楼 N_sev7 的回复:] 其实本来想移31位，判断符号位是否大于0  结果不管怎么运行都是大于0, 这里没看懂... 我vc6情况很正确啊... [/quote] 移31位没问题，问题是移了32位

user: user-6
content: 我在VS下运行了，结果是256，发现只要是移32的倍数，其结果都一样啊，是不是跟编译器有关？

user: user-4
content: 我想知道，lz是在何种情况下遇到这个坑的？我正常些代码，根本不会全移掉啊，清零的话，与或一下也行啊，是个什么样的思路？？

user: user-7
content: #include <stdio.h> unsigned char ui;   signed char si; char main() {     ui=(unsigned char)0x80u;     si=(  signed char)0x80;     printf("ui=%u\n",ui);     printf("si=%d\n",si);     ui=ui>>1;     si=si>>1;     printf("ui=%u\n",ui);     printf("si=%d\n",si);      printf("--------------\n");     ui=(unsigned char)0x80u;     si=(  signed char)0x80;     printf("ui=%u\n",ui);     printf("si=%d\n",si);     ui=((  signed char)ui)>>1;     si=((unsigned char)si)>>1;     printf("ui=%u\n",ui);     printf("si=%d\n",si);      printf("==============\n");      ui=(unsigned char)0x80u;     si=(  signed char)0x80;     printf("ui=%u\n",ui);     printf("si=%d\n",si);     ui=ui<<1;     si=si<<1;     printf("ui=%u\n",ui);     printf("si=%d\n",si);      printf("--------------\n");     ui=(unsigned char)0x80u;     si=(  signed char)0x80;     printf("ui=%u\n",ui);     printf("si=%d\n",si);     ui=((  signed char)ui)<<1;     si=((unsigned char)si)<<1;     printf("ui=%u\n",ui);     printf("si=%d\n",si);      return 0; } //ui=128 //si=-128 //ui=64 //si=-64 //-------------- //ui=128 //si=-128 //ui=192 //si=64 //============== //ui=128 //si=-128 //ui=0 //si=0 //-------------- //ui=128 //si=-128 //ui=0 //si=0

user: user-0
content: 引用 14 楼 lin5161678 的回复:[quote=引用 13 楼 N_sev7 的回复:] 可能你非常熟悉C的标准，所以对其中哪些行为是未定义的都比较清楚 理论上这样的代码不应该出现在代码里面， 但是有时候不是程序员所能控制的，比如a >> NumShift这样的语句， 当这个NumShift为32时  在Windows下用VC编译，移位的结果还是原来的数据，讨论这样的问题只是想让大家对此有所了解，不至于以后真的遇到这样的问题了不知道应该怎么处理 其实 哪怕是windows 下Vc编译 移位结果依然可能是 0   我也做不到对哪些是未定义行为都比较清楚 了解常见的几个而已  我之前说的 常识指的是  对于一段代码 当别人告诉你 那是未定义行为的时候  你索要运行结果 这行为做得不好  因为当未定义行为成立的时候 运行结果什么也说明不了 你需要确定的是 是不是真的是未定义行为  不是未定义行为 打那个人的脸  是未定义行为 默默把这段代码加入黑名单  以后写代码的时候 谨慎的不让这段代码出现 [/quote] 好的，多谢指教了！

user: user-8
content: 编译都不看警告的么？ warning C4293: '>>' : shift count negative or too big, undefined behavior

user: user-9
content: 这段代码实在是没有任何意义。 在VS2012下：warning C4293: “>>”: Shift 计数为负或过大，其行为未定义  也就是说这个右移操作根本没有执行，b直接由a的值赋值，即256。

user: user-10
content: 未定义行为, 在我这10来个编译器测试的结果是, 大部分结果是 255, 有2个编译器(Android, RVDS)结果是 0, 我猜想 mips , ppc 上也该是0, 不过懒得点板子了...

user: user-11
content: 引用 7 楼 lin5161678 的回复:>> 数值太大 实现定义  结果依赖实现  结果没有意义   >> N 可能被优化为  >> (N%32)解释很合理

user: user-11
content: b>>32；这里编译器会做什么？