C语言 文本常量和具有相同值的变量之间左移执行的差异



>我正在编写一个 C 函数,该函数接受一个参数 n 并返回一个 int,其中位表示为 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进行编译。我只需要使用以下运算符的直线代码:!˜&ˆ|+<<>>

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

int upperBits(int n) {
int retval = 0 - 1;
int shift = 32 - n;
int isnull = !(n);
printf ("%x %x %x n", retval, shift, n);
retval = retval << (shift - isnull);
retval = retval << isnull;
printf ("%x %x %x n", retval, shift, n);
return retval;
}

您正在执行非法的左移。

左移负数会调用未定义的行为,移位量大于或等于相关类型的位宽也是如此。

C 标准中关于按位移位运算符的第 6.5.7 节指出:

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

4E1 <<E2 的结果是 E1 左移 E2 位位置; 腾出的位用零填充。 如果 E1 具有未签名的 类型,结果值为 E1 × 2 E2,约模一 大于结果类型中可表示的最大值。如果 E1 具有有符号类型和非负值,并且 E1 × 2 为 可在结果类型中表示,这就是结果 价值;否则,行为是未定义的。

您可以通过使用无符号类型和检查班次的大小来更正此问题:

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

最新更新