简体   繁体   English

无符号按位移位运算符[C11]

[英]Unsigned Bitwise Shift Operators [C11]

Edit: As pointed out below I missed the first part of the ANSI C standard: " 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. " The errors (or rather lack of errors / difference in errors) are due to the particular compiler I was using. 编辑:如下所示,我错过了ANSI C标准的第一部分:“ 如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为未定义。 ”错误(或者缺少错误/错误的不同)是由于我使用的是特定的编译器。

I've come across something a bit strange, and I hope that someone can shed some light on my ignorance here. 我遇到了一些奇怪的事情,希望有人可以阐明我在这里的无知。 The necessary sample code is as follows: 必要的示例代码如下:

#include <stdio.h>
int main(void)
{
    unsigned a, b;
    int w, x, y;

    a = 0x00000001;
    b = 0x00000020;
    w = 31;
    x = 32;
    y = 33;

    a << w; /*No error*/
    a << x; /*No error*/
    a << y; /*No error*/

    a << 31; /*No error*/
    a << 32; /*Error*/
    a << 33; /*Error*/

    a << 31U; /*No error*/
    a << 32U; /*Error*/
    a << 33U; /*Error*/

    a << w + 1; /*No error*/
    a << b; /*No error*/

    return 0;
}

My question is this: why is it that an error is returned for a raw number, but not for any of the variables? 我的问题是:为什么为原始数字返回错误,而不为任何变量返回错误? They, I think, should be treated the same. 我认为,应该对它们进行同样的对待。 According to the C11 standard 根据C11标准

The result of E1 << E2 is E1 left-shifted E2 bit positions; E1 << E2的结果是E1左移E2位位置; vacated bits are filled with zeros. 空位用零填充。 If E1 has an unsigned type, the value of the result is E1 × 2^E2 , reduced modulo one more than the maximum value representable in the result type. 如果E1具有无符号类型,则结果的值为E1×2 ^ E2,比结果类型中可表示的最大值多模减少1。 If E1 has a signed type and nonnegative value, and E1 × 2 E2 is representable in the result type, then that is the resulting value; 如果E1具有带符号的类型和非负值,并且E1×2 E2在结果类型中可表示,则这是结果值; otherwise, the behavior is undefined. 否则,行为是不确定的。

The right side, since the left is unsigned type, should be 2^E2 reduced modulo one more than the maximum value representable in the result type.... That sentence isn't entirely clear to me, but in practice it seems that it is E1 << (E2%32) - despite that 32 is not the maximum representable in the result type. 右边,因为左边是无符号类型,应该比结果类型中可表示的最大值大2模比E2减少。...这句话对我来说并不完全清楚,但实际上似乎是E1 <<(E2%32)-尽管32不是结果类型中可表示的最大值。 Regardless, it is not undefined for the C11 standard, yet the error 无论如何,对于C11标准不是未定义的,但是错误

left shift count >= width of type [enabled by default] 左移计数> =类型的宽度[默认启用]

shows up when trying to compile. 尝试编译时显示。 I cannot deduce why it is that some values of >31 work (eg x = 33; a < 我无法推断出为什么> 31的某些值起作用(例如x = 33; a <

I am using the GCC compiler on 64-Bit Fedora. 我在64位Fedora上使用GCC编译器。 Thanks in advance. 提前致谢。 -Will -将

My question is this: why is it that an error is returned for a raw number, but not for any of the variables? 我的问题是:为什么为原始数字返回错误,而不为任何变量返回错误?

Because absence of compiler warnings is not a guarantee of good program behavior. 因为缺少编译器警告并不能保证良好的程序行为。 The compiler would be right to emit a warning for a << x , but it does not have to. 编译器对a << x发出警告是正确的,但并非必须如此。

They, I think, should be treated the same 我认为应该对他们进行同样的对待

The compiler is doing you a favor when it warns for a << 33 . 编译器在警告a << 33时对您有所帮助。 It is not doing you any favor when it doesn't warn for a << y , but the compiler does not have to do you any favor. 当它不为a << y发出警告时,它不会帮您任何忙,但是编译器不必帮您任何忙。

If you want to be certain that your program does not contain undefined behavior, you cannot rely on the absence of compiler warnings, but you can use a sound static analyzer. 如果要确定程序不包含未定义的行为,则可以不依赖于缺少编译器警告,但是可以使用声音静态分析器。 If a sound static analyzer for undefined behavior does not detect any in your program, then you can conclude that it does not produce any (modulo the conditions of use that would be documented for the analyzer in question). 如果用于不确定行为的声音静态分析仪未在您的程序中检测到任何东西,那么您可以得出结论,它不会产生任何声音(对要使用的分析仪记录使用条件的模数)。 For instance: 例如:

$ frama-c -val tc ... tc:13:[kernel] warning: invalid RHS operand for shift. assert 0 ≤ x < 32;

in practice it seems that it is E1 << (E2%32) 实际上,这似乎是E1 <<(E2%32)

The reason you are seeing this is that this is the behavior implemented by the shift instructions in x86_64's instruction set. 您看到的原因是,这是x86_64指令集中的shift指令实现的行为。 However, shifting by a negative number or by a number larger than the width of the type is undefined behavior . 但是, 将负号或大于类型宽度的数字移位是未定义的行为 It works differently on other architectures, and even some compiler for your architecture may compute it at compile-time (as part of the constant propagation phase) with rules that differ from the one you have noticed. 它在其他体系结构上的工作方式有所不同,甚至您体系结构的某些编译器也可能在编译时(作为恒定传播阶段的一部分)使用与您注意到的规则不同的规则对其进行计算。 Do not rely on the result being E1 << (E2%32) any more than you would rely on memory still containing the correct results after being free() d. 不要再依赖于E1 << (E2%32)的结果,而不再依赖于free() d之后仍然包含正确结果的内存。

The right side, since the left is unsigned type, should be 2^E2 reduced modulo one more than the maximum value representable in the result type.... That sentence isn't entirely clear to me, but in practice it seems that it is E1 << (E2%32) - despite that 32 is not the maximum representable in the result type. 右边,因为左边是无符号类型,应该比结果类型中可表示的最大值大2模比E2减少。...这句话对我来说并不完全清楚,但实际上似乎是E1 <<(E2%32)-尽管32不是结果类型中可表示的最大值。

That's not the correct interpretation. 那不是正确的解释。 It's the result that is modulo 2^32, not E2. 结果是模2 ^ 32,而不是E2。 That sentence is describing how bits shifted off the left side are discarded. 那句话描述的是如何丢弃从左侧移出的位。 As a result, any E2 greater than or equal to the number of bits in an int would be zero, if it were allowed. 结果,如果允许的话,任何大于或等于int位数的E2都将为零。 Since shifts greater than or equal to that number of bits are undefined behavior, the compiler is doing you the favor of producing an error at compile-time, rather than leaving it until runtime for strange and incorrect things to happen. 由于移位大于或等于该位数是未定义的行为,因此编译器帮助您在编译时生成错误,而不是将其保留到运行时才发生奇怪和不正确的事情。

For n bit of data shifting is only possible for values x>0 and x<=n-1 where x is no of bit to shift. 对于n位,仅当值x> 0x <= n-1时才可以进行数据移位,其中x是无位移位。

here in your case unsigned has memory size equals to 32 bit so only possible shifting ranges from 1 to 31. you are trying to shift data beyond the storage size of that variable that's why it is giving error to you. 在这种情况下,无符号的内存大小等于32位,因此仅可能的移位范围是1到31。您正在尝试将数据移位到超出该变量的存储大小的位置,这就是为什么会给您带来错误。

modulo one more than the maximum value representable in the result type.... 比结果类型中可表示的最大值多一个模。...

means that the value E1 * 2^E2 is reduced mod (UINT_MAX+1) for unsigned int . 表示E1 * 2^E2的值对unsigned int mod (UINT_MAX+1)降为mod (UINT_MAX+1) This has nothing at all to do with your hypothesis about E2 . 这与您关于E2的假设完全无关。

Regardless, it is not undefined for the C11 standard, 无论如何,对于C11标准,它不是未定义的,

You forgot to read the paragraph before the one you quoted: 您忘记阅读引用的段落之前的内容:

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. 如果右操作数的值为负或大于或等于提升的左操作数的宽度,则行为是不确定的。

All the shifts of 32 or more cause undefined behaviour. 所有32或更多的移位都会导致不确定的行为。 The compiler is not required to issue a warning about this, but it's being nice to you in some of the cases. 不需要编译器对此发出警告,但是在某些情况下,这对您很高兴。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM