文字常量和具有相同值的变量之间左移执行的差异

时间:2018-10-04 15:54:39

标签: c types bit-manipulation

我正在编写一个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 }}

编辑: 我仍然不知道到底是什么问题,还是一个好的解决方案,但是这种解决方法很有效:

>>

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;
    }
}