基于Linux命令dc的C语言计算器汇编除法函数负数处理问题
Looks like your assembly division routine is only handling unsigned integers right now, which is why negative values are producing garbage results. Let's break down what's happening and fix it.
The Root Cause
You're almost certainly using the div instruction in your assembly code. This instruction treats all operands as unsigned numbers. For example:
-999in 32-bit two's complement is0xFFFFFF9D- When you run
0xFFFFFF9D / 3as an unsigned calculation, you get0x55555532—which is exactly the1431655432you're seeing as the wrong result.
Negative numbers need special handling with signed division instructions and proper sign extension.
The Fix: Use Signed Division Instructions
To handle signed integers, you need to:
- Use the
idivinstruction (instead ofdiv) - Extend the sign bit of your dividend to match the size of the division operation (so the CPU recognizes it as a signed value)
Example 32-bit Assembly Function (x86)
If you're targeting 32-bit systems, here's a corrected division routine that follows the C cdecl calling convention:
.global div_signed div_signed: # Get parameters from stack: [esp+4] = dividend, [esp+8] = divisor mov eax, [esp+4] # Load dividend into EAX cdq # Sign-extend EAX to EDX:EAX (critical for signed division) idiv dword [esp+8] # Divide EDX:EAX by divisor; quotient stays in EAX ret # Return quotient in EAX (matches C's int return convention)
Example 64-bit Assembly Function (x86-64)
For 64-bit Linux (using System V AMD64 ABI, where arguments are passed in RDI, RSI):
.global div_signed div_signed: mov rax, rdi # Move dividend from RDI to RAX cqo # Sign-extend RAX to RDX:RAX idiv rsi # Divide RDX:RAX by divisor in RSI; quotient in RAX ret # Return quotient in RAX
Integrating with Your C Code
Call the assembly function from C like this (adjust types for 32/64-bit):
#include <stdio.h> // For 32-bit: extern int div_signed(int dividend, int divisor); // For 64-bit: // extern long div_signed(long dividend, long divisor); int main() { printf("-999 / 3 = %d\n", div_signed(-999, 3)); // Should output -333 printf("-999 / -3 = %d\n", div_signed(-999, -3)); // Should output 333 return 0; }
Key Notes
- Divisor Check: Don't forget to add a check in your C code (or assembly) for a divisor of 0—
idivwill trigger a CPU exception if you divide by zero. - Calling Convention: Make sure your assembly matches the C calling convention of your target platform (cdecl for 32-bit Linux, System V AMD64 for 64-bit).
- Unsigned vs Signed: Keep using
divif you need unsigned division, but switch toidiv+ sign extension for signed values.
内容的提问来源于stack exchange,提问作者Shmuel Niraev

