如何修改x86嵌入C汇编代码统计整数二进制中的0的个数?
统计二进制中0的个数的修改方案
原代码逻辑分析
原代码通过add eax, eax(等价于左移1位)将当前数的最高位移到进位标志位(CF):
jnc next:当CF为0(即移出的是0)时跳转到next,不执行计数inc ebx:仅当CF为1(即移出的是1)时执行,最终ebx存储的是二进制中1的个数
修改方案1:反转计数条件
直接修改跳转指令,当移出的是0时计数,移出的是1时跳过:
将jnc next替换为jc next,这样有进位(移出1)时跳走不计数,无进位(移出0)时执行计数。
修改后的完整代码:
int main(){ int x = 2023; // 二进制低11位为11111100111,含9个1,剩余21位为0,总0的个数为23 int y; asm( "mov eax, %1 ;" "mov ecx, 32 ;" "mov ebx, 0 ;" "loop:" "add eax, eax ;" "jc next ;" // 移出1(有进位)时跳过计数 "inc ebx ;" // 移出0(无进位)时统计 "next :" "dec ecx ;" "jnz loop;" "mov %0, ebx ;" : "=r" (y) : "r"(x) : "eax", "ebx", "ecx" ); }
注:2023的32位二进制中实际包含23个0,你之前得到的23是正确结果,并非错误。
修改方案2:总位数减去1的个数
如果不想改动核心计数逻辑,可以先统计1的个数,再用32(int类型的总位数)减去该值得到0的个数:
修改后的完整代码:
int main(){ int x = 2023; //nine 1 and two 0 as in bin it's - 11111100111 int y; asm( "mov eax, %1 ;" "mov ecx, 32 ;" "mov ebx, 0 ;" "loop:" "add eax, eax ;" "jnc next ;" "inc ebx ;" "next :" "dec ecx ;" "jnz loop;" "mov eax, 32 ;" // 加载int类型的总位数 "sub eax, ebx ;" // 总位数减去1的个数,得到0的个数 "mov %0, eax ;" : "=r" (y) : "r"(x) : "eax", "ebx", "ecx" ); }
额外注意
如果需要处理负数,由于有符号int的最高位是符号位(负数为1),统计时会包含该位。若要统计绝对值的二进制0的个数,需先对负数取绝对值后再处理。
内容的提问来源于stack exchange,提问作者pawel_duszynski
相关产品推荐
相关产品推荐

