我正在编写一个C函数,该函数接受参数n并返回一个整数,该整数的位表示形式为n 1,后跟足够的0以填充数据类型(总共32位)。我的代码当前如下所示:
int upperBits(int n) {
int retval = 0 - 1;
int shift = 32 - n;
retval = retval << shift;
return retval;
}
当n = 0时,此代码失败,返回值为-1,由32个1而不是0表示。但是,当我用文字代替shift时:
int upperBits(int n) {
int retval = 0 - 1;
int shift = 32 - n;
retval = retval << 32;
return retval;
}
代码正常工作,返回0。当使用n = 0调用函数时,我使用了print语句来验证shift = 32,所以我不明白为什么它们的行为不同。是什么导致了这种差异,我该如何规避呢?
如果相关,则代码在Linux计算机上运行,并使用gcc进行编译。我只需要对这些运算符使用直线代码:!
˜
&
ˆ
|
+
<<
{{1 }}
编辑: 我仍然不知道到底是什么问题,还是一个好的解决方案,但是这种解决方法很有效:
>>
答案 0 :(得分:5)
您正在执行非法的左移。
向左移负数会调用undefined behavior,向左移大于或等于所讨论类型的位宽度的量也会引起这种情况。
C standard中有关按位移位运算符的第6.5.7节指出:
3 对每个操作数执行整数提升。结果的类型是提升后的左操作数的类型。 如果 右操作数的值是负数或大于 或等于提升的左操作数的宽度,其行为是 未定义。
4 E1 << E2的结果是E1左移E2位位置; 空位用零填充。如果E1具有未签名 类型,结果值为E1×2 E2,以模为底 大于结果类型可表示的最大值。 如果E1具有带符号的类型和非负值,并且E1×2 E2为 在结果类型中可以表示,那么就是结果 值;否则,行为是不确定的。
您可以使用无符号类型并检查班次的大小来纠正此问题:
uint32_t upperBits(int n) {
uint32_t retval = 0xffffffff;
if (n <= 0 || n > 32) {
return 0;
} else {
int shift = 32 - n;
retval = retval << shift;
return retval;
}
}