我遇到了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
答案 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_t
和uint32_t
由linux / types.h
stdint.h
提供。你应该#include <stdint.h>
得到它们,即使它们也是由linux/types.h
在你的系统上提供的,因为那是可移植的解决方案。
答案 1 :(得分:0)
我在这里看到的唯一可能的解释是,不会调用预期的掩码函数。 请仅在一个文件中尝试您的示例代码,和/或重命名掩码功能。 您的值(0x10000)的位和(nr&amp; 0x1ff)应始终为零。