装配ADC(随附进位)到C ++

时间:2010-11-11 11:21:08

标签: c++ assembly x86

有汇编指令ADC。我发现这意味着“随身携带”。但我不知道 意味着什么。或者如何用C ++编写这个指令。我知道它与ADD不一样。所以做一个简单的求和是不正确的。

信息:
在Windows中编译。我正在使用32位Windows安装。我的处理器是英特尔的Core 2 Duo。

6 个答案:

答案 0 :(得分:22)

ADC与ADD相同,但如果设置了处理器的进位标志,则会额外增加1。

答案 1 :(得分:7)

来自here(已破损)或here

  

但是,英特尔处理器   有一个叫做adc的特殊指令。   此命令的行为与   添加命令。唯一的额外的事情是   它还添加了值进位标志   沿。所以,这可能非常方便   添加大整数。假设你喜欢   添加一个16位的32位整数   寄存器。我们怎么做?好,   让我们说第一个整数是   寄存器对DX:AX,和   第二个是BX:CX。这是   方法:

add  ax, cx
adc  dx, bx
     

啊,首先,低16位被添加   添加ax,cx。然后是更高的16位   使用adc而不是add添加。它是   因为:如果有溢出,   进位自动添加   更高的16位。所以,没有繁琐   检查。这种方法可以扩展   到64位等等...注意:如果   32位整数加法溢出   在更高的16位,结果也是如此   将不正确和进位标志   设定,例如增加50亿到5   十亿。

从这里开始的一切,请记住,它几乎落入了实现定义行为的区域。

这是一个适用于VS 2010(32位,WinXp)的小样本

警告:$ 7.4 / 1-“asm声明是有条件支持的;它的含义是实现定义的。[注意:通常它用于通过实现将信息传递给汇编程序。-end note]”

int main(){
   bool carry = false;
   int x = 0xffffffff + 0xffffffff;
   __asm {
      jc setcarry
setcarry:
      mov carry, 1
   }
}

答案 2 :(得分:6)

可以在C和C ++中模拟ADC行为。以下示例添加了两个数字(存储为unsigned数组,因为它们太大而无法放入单个无符号数组中)。

unsigned first[10];
unsigned second[10];
unsigned result[11];

....   /* first and second get defined */

unsigned carry = 0;
for (i = 0; i < 10; i++) {
    result[i] = first[i] + second[i] + carry;
    carry = (first[i] > result[i]);
}
result[10] = carry;

希望这有帮助。

答案 3 :(得分:4)

这有一个错误。试试这个输入:

unsigned first[10] =  {0x00000001};
unsigned second[10] = {0xffffffff, 0xffffffff};

结果应为{0,0,1,...}但结果为{0,0,0,...}

更改此行:

carry = (first[i] > result[i]);

到此:

if (carry)
    carry = (first[i] >= result[i]);
else
    carry = (first[i] > result[i]);

修复它。

答案 4 :(得分:3)

C ++语言没有任何进位标志的概念,因此围绕ADC instruction制作内在函数包装器是笨重的。但是,英特尔无论如何都做到了:unsigned char _addcarry_u32 (unsigned char c_in, unsigned a, unsigned b, unsigned * out);。最后我检查了一下,gcc做得很差(将进位结果保存到整数寄存器中,而不是将其保留在CF中),但希望英特尔自己的编译器做得更好。

另请参阅标记wiki以获取程序集文档。

当添加比单个寄存器更宽的整数时,编译器将为您使用ADC,例如:在32位代码中添加int64_t,或在64位代码中添加__int128_t

#include <stdint.h>
#ifdef __x86_64__
__int128_t add128(__int128_t a, __int128_t b) { return a+b; }
#endif
    # clang 3.8 -O3  for x86-64, SystemV ABI.
    # __int128_t args passed in 2 regs each, and returned in rdx:rax
    add     rdi, rdx
    adc     rsi, rcx
    mov     rax, rdi
    mov     rdx, rsi
    ret

来自Godbolt compiler explorer的asm输出。 clang的-fverbose-asm并不是很宽松,但gcc 5.3 / 6.1浪费了两条mov指令,因此它的可读性较差。

答案 5 :(得分:0)

unsigned long result;
unsigned int first;
unsigned int second;

result = first + second;
result += (result & 0x10000) ? 1 : 0;
result &= 0xFFFF