装配ADC(随附进位)到C ++
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装配ADC(随附进位)到C ++相关的知识,希望对你有一定的参考价值。
有一个汇编指令ADC
。我发现这意味着“随身携带”。但我不知道这意味着什么。或者如何用C ++编写这个指令。我知道这与ADD
不一样。所以做一个简单的求和是不正确的。
信息: 在Windows中编译。我正在使用32位Windows安装。我的处理器是Intel的Core 2 Duo。
ADC与ADD相同,但如果处理器的进位标志置位则增加1。
但是,英特尔处理器有一条名为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中),但希望英特尔自己的编译器做得更好。
另请参阅x86标记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 ++的主要内容,如果未能解决你的问题,请参考以下文章
Android:如何在选项卡内从一个片段导航到另一个片段? [关闭]
C语言习题如何在 C 中不使用任何分号打印从 1 到 N 的数字?
编写一个程序, 将 a.txt 文件中的单词与 b.txt 文件中的 单词交替合并到 c.txt 文件中, a.txt 文件中的单词用回车符 分隔, b.txt 文件中用回车或空格进行分隔。(代码片段