是否将8 * sizeof(int)或更多未定义的签名int右移?

时间:2016-09-27 16:01:12

标签: c undefined-behavior bit-shift

我知道这是未定义的:

uint32_t u = 1;
u << 32;

但我对于哪种类型的转变未定义感到有些困惑。

是否未定义将有符号整数按其大小(以位为单位)或更多向右移位?

更新:正如答案中所指出的,这是以位为单位的大小,而不是以字节为单位。

3 个答案:

答案 0 :(得分:6)

sizeof (int)的大小为int ,以字节为单位,因此无关紧要。相关的不是大小,而是 width ,它是表示中的值位数(加上有符号类型的符号位)。

如果<<>>运算符的右操作数大于或等于提升的左操作数的宽度,则行为未定义。 (例如,如果左操作数的类型为short,则在应用操作之前将其提升为int

对于<<左移运算符,仅当左操作数为非负且结果可表示时才定义行为。

对于>>右移运算符,如果左操作数为负,则结果为实现定义。

这一点在C standard的第6.5.7节中定义(链接是N1570,最近公开发布的C11草案)。

以下是语义的完整描述:

  

对每个操作数执行整数提升。该   结果的类型是提升的左操作数的类型。如果值   右操作数是负数还是大于或等于   提升左操作数的宽度,行为未定义。

     

E1 << E2 的结果是 E1 左移 E2   位位置;腾出的位用零填充。如果 E1   有一个无符号类型,结果的值是 E1 ×    2 E2 ,减少模数超过最大值   值可在结果类型中表示。如果 E1 具有签名类型   和非负值, E1 × 2 E2 是   在结果类型中可表示,那么这就是结果值;   否则,行为未定义。

     

E1 >> E2 的结果是 E1 右移 E2 位   位置。如果 E1 具有未签名类型或 E1 已签名   类型和非负值,结果的值是积分    E1 / 2 E2 的商数的一部分。如果    E1 具有签名类型和负值,即结果值   是实现定义的。

答案 1 :(得分:2)

标准中的一切。 Section 6.5.7p3

  

3)对每个操作数执行整数提升。该   结果的类型是提升的左操作数的类型。如果值   右操作数的负数或大于或等于   提升左操作数的宽度,行为未定义

这适用于左移和右移,以及运算符左侧的有符号和无符号操作数。移位已签名的操作数还有其他限制。

答案 2 :(得分:0)

在编写C89标准之前,C语言被广泛使用,C89标准的作者不希望对角落语义提出任何要求,这可能与现有实现已经在做的任何事情相反。< / p>

某些实现在给定非常大或负数时会表现不佳 转移金额(例如,我认为在Transputer上转移-1将需要大约 4294967295执行时钟周期,在此期间中断将是 当被要求按字长移动时,有些实现 根本不会改变。标准的作者没有理由区分这些行为,只是将字大小视为阈值,超出该阈值就不会产生任何要求。

虽然使用格式时负面值的正确含义尚不清楚 除了两个补码之外,两个补码没有真正的模糊性 超出一些现有实施使用逻辑权利的事实 - 即使使用带符号的类型和转换,也不是算术右移 委员会并不想要求任何现有的编译器改变行为 该代码可能依赖于它。在格式中使用负值时 除了两个补充之外,它还不清楚两个方向的变化 应该意味着,但委员会认为更有可能存在 一个机器,当左移一个负数时会做一些奇怪的事情 当一个负面转移时,机器可能会做一些奇怪的事情 号。

请注意,质量编译器的概念如下:

unsigned long rotate_left(unsigned long dat, int amount)
{ return (dat << amount) | (dat >> (32-amount)); }

应该做除收益以外的任何事情&#34; dat&#34;当金额== 0时[注意这两个 评估右移的常用方法会产生相同的结果 相对较新。我认为C89的作者打算如果质量 平台X的编译器可能会在某种程度上表现出来 C89已经发布,根据标准,这种行为是允许的, 该平台的质量编译器应继续以这种方式运行。 尽管如此,一种态度已经出现,不应该允许程序员 依赖于标准未规定的任何行为,即使在平台上也是如此 它们将是有用和便宜的。