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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装配ADC(随附进位)到C ++相关的知识,希望对你有一定的参考价值。

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

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

答案

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

另一答案

来自here(破碎)或here

但是,英特尔处理器有一条名为adc的特殊指令。此命令的行为与add命令类似。唯一的额外的事情是它还添加值进位标志。因此,添加大整数可能非常方便。假设您要添加带有16位寄存器的32位整数。我们怎么做?好吧,假设第一个整数保存在寄存器对DX:AX上,第二个整数保存在BX:CX上。这是如何:

add  ax, cx
adc  dx, bx

啊,首先,通过add ax,cx添加低16位。然后使用adc而不是add添加更高的16位。这是因为:如果存在溢出,则进位位会自动添加到更高的16位中。所以,没有繁琐的检查。这种方法可以扩展到64位,依此类推......注意:如果32位整数加法在高16位处也溢出,结果将不正确并且进位标志被设置,例如,增加50亿至50亿。

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

这是一个适用于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
   }
}
另一答案

可以在C和C ++中模拟ADC行为。下面的示例添加了两个数字(存储为unsigned数组,因为它们太大而无法放入单个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;

希望这可以帮助。

另一答案

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

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]);

解决它。

另一答案

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指令,因此它的可读性较差。

另一答案
unsigned long result;
unsigned int first;
unsigned int second;

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

以上是关于装配ADC(随附进位)到C ++的主要内容,如果未能解决你的问题,请参考以下文章

如何正确编组从Unity到C / C ++的字符串?

Android:如何在选项卡内从一个片段导航到另一个片段? [关闭]

C语言习题如何在 C 中不使用任何分号打印从 1 到 N 的数字?

编写一个程序, 将 a.txt 文件中的单词与 b.txt 文件中的 单词交替合并到 c.txt 文件中, a.txt 文件中的单词用回车符 分隔, b.txt 文件中用回车或空格进行分隔。(代码片段

在Visual Studio 2010中将Native / C ++ DLL链接到托管C ++ / CLI包装器

latex在vim中的代码片段