C右移无法在我的程序中的int类型上正常工作

问题描述:

我在C语言中具有以下功能:

I have the following function in C:

int lrot32(int a, int n)
{
    printf("%X SHR %d = %X\n",a, 32-n, (a >> (32-n)));
    return ((a << n) | (a >> (32-n)));
}

当我将lrot32(0x8F5AEB9C,0xB)作为参数传递时,我得到以下信息:

When I pass as arguments lrot32(0x8F5AEB9C, 0xB) I get the following:

8F5AEB9C shr 21 = FFFFFC7A

但是,结果应为47A.我在做什么错了?

However, the result should be 47A. What am I doing wrong?

谢谢您的时间

int是带符号的整数类型. C11 6.5.7p4-5 表示以下内容:

int is a signed integer type. C11 6.5.7p4-5 says the following:

4 E1 << E2的结果是E1左移E2位的位置;空位用零填充. [...]如果E1具有带符号的类型和非负值,并且 E1 x 2 E2 在结果类型中是可表示的,那么它就是结果值;否则,行为是不确定的.

4 The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. [...] If E1 has a signed type and nonnegative value, and E1 x 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

5 E1 >> E2的结果是E1右移E2位的位置. [...]如果E1具有带符号的类型和非负值,则结果的值是E1/2 E2 的商的整数部分. 如果E1具有带符号的类型和负值,则结果值是实现定义的.

5 The result of E1 >> E2 is E1 right-shifted E2 bit positions. [...] if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2 . If E1 has a signed type and a negative value, the resulting value is implementation-defined.

因此,在<<的情况下,如果移位值为负,或者移位后的正值无法在结果类型中表示(此处为int),则行为是不确定的;对于>>,如果该值为负,则结果是定义的实现.

Thus in the case of <<, if the shifted value is negative, or the positive value after shift is not representable in the result type (here: int), the behaviour is undefined; in the case of >>, if the value is negative the result is implementation defined.

因此,在任何一种情况下,您得到的结果至少都取决于实现,对于左移情况,则更糟,可能取决于优化级别等.严格遵循的程序不能依赖任何特定的行为.

Thus in either case, you'd get results that at least depend on the implementation, and in the case of left-shift, worse, possibly on the optimization level and such. A strictly conforming program cannot rely on any particular behaviour.

但是,如果您要针对特定​​的编译器,请查看其手册,以了解行为(如果指定了行为).例如 GCC说 :

If however you want to target a particular compiler, then check its manuals on what the behaviour - if any is specified - would be. For example GCC says:

对有符号整数进行一些按位运算的结果(C90 6.3, C99和C11 6.5).

The results of some bitwise operations on signed integers (C90 6.3, C99 and C11 6.5).

按位运算符作用于值的表示形式,包括 符号位和值位,其中考虑了符号位 在最高值位的正上方. 签署">>"的行为 负号后加符号扩展名. [*]

Bitwise operators act on the representation of the value including both the sign and value bits, where the sign bit is considered immediately above the highest-value value bit. Signed ‘>>’ acts on negative numbers by sign extension. [*]

作为C语言的扩展, GCC不使用给定的纬度 在C99和C11中仅将带符号的<<"的某些方面视为 .但是,-fsanitize = shift(和-fsanitize = undefined)将 诊断此类情况.他们还被诊断出恒定 表达式是必需的.

As an extension to the C language, GCC does not use the latitude given in C99 and C11 only to treat certain aspects of signed ‘<<’ as undefined. However, -fsanitize=shift (and -fsanitize=undefined) will diagnose such cases. They are also diagnosed where constant expressions are required.

[*]符号扩展在这里意味着符号位-对于负整数是1,在执行右移时会重复移位量-这就是为什么在结果中看到那些F的原因.

[*] sign extension here means that the sign bit - which is 1 for negative integers, is repeated by the shift amountwhen right-shift is executed - this is why you see those Fs in the result.

此外,GCC始终需要2的补码表示法,因此,如果您始终 使用GCC,无论您针对的是哪种架构,这都是您所看到的行为.另外,将来有人可能会为您的代码使用其他编译器,从而在此处引起其他行为.

Furthermore GCC always requires 2's complement representation, so if you would always use GCC, no matter which architecture you're targeting, this is the behaviour you'd see. Also, in the future someone might use another compiler for your code, thus causing other behaviour there.

也许您想使用无符号整数-unsigned int,或者更确切地说,如果期望一定的宽度,那么例如uint32_t,因为移位始终是明确定义的,并且似乎与您的移位匹配期望.

Perhaps you'd want to use unsigned integers - unsigned int or rather, if a certain width is expected, then for example uint32_t, as the shifts are always well-defined for it, and would seem to match your expectations.

要注意的另一件事是,并非所有班次金额都被允许. C11 6.5.7 p3 :

Another thing to note is that not all shift amounts are allowed. C11 6.5.7 p3:

[...]如果右操作数的值为负或大于或等于提升后的左操作数的宽度,则行为不确定.

[...]If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

因此,如果您将宽度为32位的无符号整数左移或右移32,则行为为未定义.应该牢记这一点.即使编译器不会做任何古怪的事情,某些处理器体系结构的行为也确实好像先移位32位然后将所有位都移开了,而其他处理器的行为就好像移位量为0.

Thus if you ever shift an unsigned integer having width of 32 bits by 32 - left or right, the behaviour is undefined. This should be kept in mind. Even if the compiler wouldn't do anything wacky, some processor architectures do act as if shift by 32 would then shift all bits away - others behave as if the shift amount was 0.