左移溢出

时间:2016-02-05 00:00:31

标签: c bit-manipulation bitwise-operators

当我离开已签名的字符时,我不认为我完全理解c编译器中发生了什么。我用值0x8d<<初始化它了3,它给了我一个警告:隐式常量转换溢出。我假设它是因为它给了一个很大的char值,但是当我手工完成时我会得到104作为答案。

所以这意味着当价值被转移时它正在做

10001101 << 3 = 10001101000

而不是

10001101 << 3 = 01101000

想出来,但这是代码:

signed char testChar = 0x8d << 3;
printf("testChar : %d\n", testChar);

只需要正常初始化它然后将它转移到另一条线上,超级简单的东西。

2 个答案:

答案 0 :(得分:1)

您的问题很混乱:您是否正在使用值0x8d << 3初始化已签名的字符?这显然是实现定义为值超出类型范围并且类型已签名。编译器发出警告,因为精度损失是明确的。

相反,如果你的意思是左移一个签名的字符,左移一个值为0x8d的签名字符,这又是不正确的:除非char有超过8位,有符号的char不能具有0x8d的值。它的值-115可以具有相同的位模式。左移这将以这种方式计算:

  • char值首先提升为int
  • int值左移3但位置:相当于乘以8。
  • 如果值为负,则标准表示行为未定义,但大多数使用2s补码表示负值的当前处理器将产生与乘以8相同的结果。

结果值为-920。此值不适合char。将其存储到char是实现定义的。最可能的结果是char值为104

修改

您发布了实际代码:

signed char testChar = 0x8d << 3;
printf("testChar : %d\n", testChar);

如果char是8位,则赋值具有实现定义的行为,因为1128超出了类型signed char(-128..127)的范围,这是大多数现代处理器上的行为是掩盖高阶位并将8个低阶位存储到目标字节中,就好像它是unsigned char一样。在您的情况下,结果是1128 & 255 - &gt; 104

答案 1 :(得分:0)

您还没有显示您的实际代码(见下文),但您提供了足够的信息来推断它:

signed char c = 0x8d << 3;

常量0x8d的类型为int。将其左移3位会产生值0x468,或等效1128

初始化会隐式地将该值从int转换为signed char。由于该值超出了signed char的范围(可能会有-128+127的范围,除非您使用非常奇怪的系统),结果是实现 - 定义。通常会丢弃高位,这会产生0x68104的结果。

编译器警告您,您正在将值1128转换为signed char,这不足以容纳它。

也许您希望0x8d属于signed char类型?它不是。表达式的类型几乎总是由表达式本身决定,而不是由它出现的上下文决定。整数常量(十进制,十六进制或八进制)始终为int类型,除非它们超过INT_MAX的值,该值至少为32767(可能为2147483647 )。 (或者除非他们有LU这样的后缀,但这里没有相关内容。)

更新:

您已向我们展示了原始代码:

signed char testChar = 0x8d << 3;
printf("testChar : %d\n", testChar);

我希望这会产生警告,因为您用来初始化1128的值testChar会导致溢出。存储在testChar中的值是实现定义的,但它很可能是104,这是丢弃高位的结果。

如果您将班次分成单独的作业:

signed char testChar = 0x8d;
testChar = testChar << 3;

然后我期待相同的结果。但是值0x8d太大而无法存储在signed char中,因此转换会产生实现定义的结果 - 很可能是-115。负值的左移有未定义的行为 - 但同样,它可能会产生-920,转换为signed char时可能会给你104

最终,您的问题的解决方案是做一些不同于您尝试做的事情。值0x8d << 3将不适合signed char,任何使其适合的尝试都必然会导致问题。通过调整代码,您可能会设法使编译器的警告静音,但您仍然在做一些没有用的事情。