移位计数大于类型的宽度

时间:2018-10-12 17:31:44

标签: c types

我有一个使用int data_length并执行以下操作的函数:

unsigned char *message = (unsigned char*)malloc(65535 * sizeof(char));
message[2] = (unsigned char)((data_length >> 56) & 255);

我得到以下信息:

warning: right shift count >= width of type [-Wshift-count-overflow]
   message[2] = (unsigned char)((data_length >> 56) & 255);

程序可以按预期工作,但是如何删除编译器警告(不禁用它)? 类似的问题似乎没有使用变量作为要插入的数据,因此似乎解决方案是将其强制转换为int或此类。

2 个答案:

答案 0 :(得分:2)

标准不允许移动大于所讨论类型的位宽的量,并且这样做会调用undefined behavior

这在C standard的6.5.7p3节中详细介绍了按位移位运算符。

  

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

如果程序似乎正在运行,很幸运。您可以对程序进行不相关的更改,也可以仅在其他计算机上构建它,然后突然一切停止运转。

如果data_length的大小为32位或更小,则向右移56将太大。您只能平移0-31。

答案 1 :(得分:1)

问题很简单。当您将data_length用作int时,应该使用 unsigned ,因为负长度几乎没有意义。为了能够移位56位,值必须至少宽 56 57位。否则,行为是不确定的。

在实践中,处理器的功能千差万别。在一个例子中,将32位值右移32位将清除变量。在另一个值中,该值移位0位(32 % 32!)。然后,在某些情况下,也许处理器认为它是无效的操作码,并且操作系统终止了该进程。

简单的解决方案:声明uint64_t data_length


如果您确实将自己限制为32位数据类型,则只需将0分配给这些表示最高有效字节的字节即可。或者只是在转换前强制转换为uint64_tunsigned long long