【发布时间】:2016-02-29 05:30:42
【问题描述】:
我正在使用 bt 来测试在汇编中是否设置了某些位。我的代码如下所示:
#define bv %eax //just renaming reg to make reading easier
#define bit %edx //rename reg
/*
* bitIsSetBV(unsigned int *bv, unsigned int bit)
* this function returns 0 if bit at location bit is not set
* it returns 1 if it is set
*/
.text
.global bitIsSetBV
bitIsSetBV:
movl 4(%esp), bv //make room on stack for bv
movl 8(%esp), bit //make room on stack for bit
bt bit, (bv) //if bv[bit] is 0, set CF to 0, else, set CF to 1
jc bitSet // if CF is 1, jump to bitSet
jnc bitNotSet // if CF is 0, jump to bitNotSet
bitNotSet:
movl $0, bv //return 0, bit is not set
jmp Done // jump to Done
bitSet:
movl $1, bv // return 1, bit is set
jmp Done // jump to Done
Done:
ret //end of code
测试人员:
assert(bitIsSetBV(bv, 0) == 1); // 0001 assert(bitIsSetBV(bv, 1) == 0); assert(bitIsSetBV(bv, 2) == 0); assert(bitIsSetBV(bv, 3) == 0); assert(bitIsSetBV(bv, 4) == 0); // 1110 assert(bitIsSetBV(bv, 5) == 1); assert(bitIsSetBV(bv, 6) == 1); assert(bitIsSetBV(bv, 7) == 1);
我的代码适用于 bit = 0-5,但在 bit = 6 时却不行。这是为什么?我确定这是我对位级操作的误解。
【问题讨论】:
-
just renaming reg to make reading easier这个评论很有趣。我什至没有看这两行,而是看了你的代码,想知道BT是如何使用几个内存操作数的。也许我变老了,但是这两个定义使代码更难遵循 lol -
您没有向我们展示定义
bv的测试C 代码,因此我们不知道它是如何实际定义和分配的。尽管您的代码效率低下,但这种冗余是完全没有必要的:jnc bitNotSet。删除该行,因为您之前已经测试过是否在指令上设置了进位,因此如果它通过,则不得设置。它会一直执行到下一条指令,该指令恰好是bitNotSet的代码。jmp Done之前的标签Done也可以删除,因为您正在跳转到下一条指令。 -
movl 4(%esp), bv //make room on stack for bv该代码的注释不匹配。堆栈已经保存了这些值,您正在将它们复制到寄存器中。你不是making room在堆栈上的他们。 -
bt bit, (bv) //if bv[bit] is 0, set CF to 0, else, set CF to 1这个bv[bit]怎么样?这只是取消引用bv并测试bit的位...您如何在C 代码中定义bv? -
不要在进位标志上分支,而是使用
xor %eax,%eax / bt / setc %al。