位掩码+类型转换不会按预期返回

时间:2013-03-19 13:45:54

标签: c type-conversion bit-manipulation

我遇到了bitmasking和/或类型转换不能按预期工作的情况。我正在使用一个压倒性的大型分布式系统,其中一些部分是我写的。

令我困惑的几行代码是:

uint16_t
mask(uint32_t nr)
{
  return (uint16_t)(nr & 0x1ff);
}

...

  int nr = 65536;
  int index;
  index = mask(nr);

...

在这种情况下,掩码的返回值为65536,而不是预期的0。在这个例子中有一些不一致的类型转换,但我无法理解结果是如何错误的。我们基本上屏蔽了32位整数的低9位并将结果转换为16位整数。我最好的猜测是,有一些编译器优化会改变前16位,但对高16位没有任何作用,因为我们只想返回16位。由于在这种情况下'索引'是一个32位整数,这也包括'nr'的第17位,它在位掩码中没有被修改,因此第17位仍设置为1并将65536分配给索引

是否有人对此行为有解释?

编辑: 我忘了一些重要的参数。 适当地包括掩模功能的原型。该系统是为带有gcc 4.3.2的Linux x86构建的。

EDIT2: 汇编代码:

0805b640 <mask>:
 805b640:       55                      push   %ebp
 805b641:       89 e5                   mov    %esp,%ebp
 805b643:       83 ec 18                sub    $0x18,%esp
 805b646:       65 a1 14 00 00 00       mov    %gs:0x14,%eax
 805b64c:       89 45 fc                mov    %eax,0xfffffffc(%ebp)
 805b64f:       31 c0                   xor    %eax,%eax
 805b651:       8b 45 08                mov    0x8(%ebp),%eax
 805b654:       66 25 ff 01             and    $0x1ff,%ax
 805b658:       8b 55 fc                mov    0xfffffffc(%ebp),%edx
 805b65b:       65 33 15 14 00 00 00    xor    %gs:0x14,%edx
 805b662:       75 02                   jne    805b666 <maks+0x26>
 805b664:       c9                      leave  
 805b665:       c3                      ret    
 805b666:       e8 a5 ac 04 00          call   80a6310 <__stack_chk_fail_local>
 805b66b:       90                      nop    
 805b66c:       8d 74 26 00             lea    0x0(%esi),%esi

2 个答案:

答案 0 :(得分:2)

这是我的gcc(4.6.2)从mask产生的(有优化;没有,它周围有一些毛茸茸):

.LFB0:
    .cfi_startproc
    movl    4(%esp), %eax
    andw    $511, %ax
    ret
    .cfi_endproc

所以它确实只修改了低16位,并且调用者有责任实际将每个高位16位清零

movzwl  %ax, %eax

如果在呼叫站点知道正确的原型,它会这样做。我非常强烈怀疑

  

正确包含了掩码功能的原型。

实际上不是真的,检查并重新检查。如果确实如此,那么你发现了一个主要的错误(我们可能已经听说过它很重要)。

  

uint16_tuint32_t由linux / types.h

提供
嗯,不是在这里。它们由stdint.h提供。你应该#include <stdint.h>得到它们,即使它们也是由linux/types.h在你的系统上提供的,因为那是可移植的解决方案。

答案 1 :(得分:0)

我在这里看到的唯一可能的解释是,不会调用预期的掩码函数。 请仅在一个文件中尝试您的示例代码,和/或重命名掩码功能。 您的值(0x10000)的位和(nr&amp; 0x1ff)应始终为零。